/ Check-in [cc3f6542]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix further issues with multi-column IN(...) operators. Also some error handling cases surrounding row values.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rowvalue
Files: files | file ages | folders
SHA1: cc3f6542bec99b00d2698889bcea2aa0b587efa0
User & Date: dan 2016-07-28 19:47:15
Context
2016-07-29
18:12
Change the way "(a, b) = (SELECT *)" expressions are handled in where.c if there is an index on one of the columns only. check-in: 4dfebff2 user: dan tags: rowvalue
2016-07-28
19:47
Fix further issues with multi-column IN(...) operators. Also some error handling cases surrounding row values. check-in: cc3f6542 user: dan tags: rowvalue
13:59
Merge latest trunk changes into this branch. check-in: 9685880f user: dan tags: rowvalue
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
....
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
....
1899
1900
1901
1902
1903
1904
1905

















1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
....
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008

2009
2010
2011
2012
2013
2014
2015
....
2347
2348
2349
2350
2351
2352
2353


























2354
2355
2356
2357
2358
2359
2360
....
2383
2384
2385
2386
2387
2388
2389

2390
2391
2392
2393
2394
2395

2396
2397
2398
2399
2400
2401
2402
....
2475
2476
2477
2478
2479
2480
2481







2482
2483

2484
2485
2486
2487
2488
2489
2490
....
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503





2504
2505
2506
2507
2508

2509
2510
2511
2512
2513

2514



2515

2516
2517
2518

2519
2520
2521
2522
2523
2524
2525
2526



2527

2528
2529
2530
2531







2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
....
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
....
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
....
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
....
3941
3942
3943
3944
3945
3946
3947

3948
3949
3950
3951
3952
3953
3954
....
3987
3988
3989
3990
3991
3992
3993

3994
3995
3996
3997
3998
3999
4000
** used in a context in which there is no difference between a result
** of 0 and one of NULL. For example:
**
**     ... WHERE (?,?) IN (SELECT ...)
**
*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(Expr *pX, int bNullSensitive){
  Select *p;
  SrcList *pSrc;
  ExprList *pEList;
  Table *pTab;
  int i;
  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
................................................................................
  if( pSrc->a[0].pSelect ) return 0;     /* FROM is not a subquery or view */
  pTab = pSrc->a[0].pTab;
  assert( pTab!=0 );
  assert( pTab->pSelect==0 );            /* FROM clause is not a view */
  if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
  pEList = p->pEList;

  /* All SELECT results must be columns. If the SELECT returns more than
  ** one column and the bNullSensitive flag is set, all returned columns
  ** must be declared NOT NULL. */
  for(i=0; i<pEList->nExpr; i++){
    Expr *pRes = pEList->a[i].pExpr;
    if( pRes->op!=TK_COLUMN ) return 0;
    assert( pRes->iTable==pSrc->a[0].iCursor );  /* Not a correlated subquery */
    if( pEList->nExpr>1 && bNullSensitive ){
      if( pTab->aCol[pRes->iColumn].notNull==0 ) return 0;
    }
  }
  return p;
}
#endif /* SQLITE_OMIT_SUBQUERY */

/*
** Code an OP_Once instruction and allocate space for its flag. Return the 
................................................................................
  int eType = 0;                        /* Type of RHS table. IN_INDEX_* */
  int iTab = pParse->nTab++;            /* Cursor of the RHS table */
  int mustBeUnique;                     /* True if RHS must be unique */
  Vdbe *v = sqlite3GetVdbe(pParse);     /* Virtual machine being coded */

  assert( pX->op==TK_IN );
  mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;


















  /* Check to see if an existing table or index can be used to
  ** satisfy the query.  This is preferable to generating a new 
  ** ephemeral table.
  */
  if( pParse->nErr==0 && (p = isCandidateForInOpt(pX, prRhsHasNull!=0))!=0 ){
    sqlite3 *db = pParse->db;              /* Database connection */
    Table *pTab;                           /* Table <table>. */
    i16 iDb;                               /* Database idx for pTab */
    ExprList *pEList = p->pEList;
    int nExpr = pEList->nExpr;

    assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
................................................................................
          int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
          sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
          sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
          VdbeComment((v, "%s", pIdx->zName));
          assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
          eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];

          if( prRhsHasNull && nExpr==1 
           && !pTab->aCol[pEList->a[0].pExpr->iColumn].notNull 
          ){
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
            i64 mask = (1<<nExpr)-1;
            sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, 
                iTab, 0, 0, (u8*)&mask, P4_INT64);
#endif
            *prRhsHasNull = ++pParse->nMem;
            sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);

          }
          sqlite3VdbeJumpHere(v, iAddr);
        }
      }
    }
  }

................................................................................
    sqlite3VdbeJumpHere(v, jmpIfDynamic);
  }
  sqlite3ExprCachePop(pParse);

  return rReg;
}
#endif /* SQLITE_OMIT_SUBQUERY */



























#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate code for an IN expression.
**
**      x IN (SELECT ...)
**      x IN (value, value, ...)
................................................................................
  int *aiMap = 0;       /* Map from vector field to index column */
  char *zAff = 0;       /* Affinity string for comparisons */
  int nVector;          /* Size of vectors for this IN(...) op */
  int regSelect = 0;
  Expr *pLeft = pExpr->pLeft;
  int i;


  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
  aiMap = (int*)sqlite3DbMallocZero(
      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
  );
  if( !aiMap ) return;
  zAff = (char*)&aiMap[nVector];


  /* Attempt to compute the RHS. After this step, if anything other than
  ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable 
  ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
  ** the RHS has not yet been coded.  */
  v = pParse->pVdbe;
  assert( v!=0 );       /* OOM detected prior to this routine */
................................................................................
      sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfFalse);
    }
    sqlite3VdbeResolveLabel(v, labelOk);
    sqlite3ReleaseTempReg(pParse, regCkNull);
  }else{
  







    /* If the LHS is NULL, then the result is either false or NULL depending
    ** on whether the RHS is empty or not, respectively.  */

    if( destIfNull==destIfFalse ){
      for(i=0; i<nVector; i++){
        Expr *p = exprVectorField(pExpr->pLeft, i);
        if( sqlite3ExprCanBeNull(p) ){
          sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull);
        }
      }
................................................................................
      sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
      VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfNull);
      sqlite3VdbeJumpHere(v, addr1);
    }
  
    if( eType==IN_INDEX_ROWID ){
      /* In this case, the RHS is the ROWID of table b-tree
      */
      sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1);
      VdbeCoverage(v);





    }else if( nVector>1 && eType==IN_INDEX_EPH && destIfNull!=destIfFalse ){
      int regNull = sqlite3GetTempReg(pParse);
      int r2 = sqlite3GetTempReg(pParse);
      int r3 = sqlite3GetTempReg(pParse);
      int r4 = sqlite3GetTempReg(pParse);

      int addrNext;
      int addrIf;

      if( destIfFalse!=destIfNull ){
        sqlite3VdbeAddOp2(v, OP_Integer, 0, regNull);

      }



      addrNext = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);

      for(i=0; i<nVector; i++){
        Expr *p;
        CollSeq *pColl;

        p = exprVectorField(pLeft, i);
        pColl = sqlite3ExprCollSeq(pParse, p);

        sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r2);
        sqlite3VdbeAddOp4(v, OP_Eq, r1+i, i?r3:r4, r2, (void*)pColl,P4_COLLSEQ);
        sqlite3VdbeChangeP5(v, SQLITE_STOREP2);
        if( i!=0 ){
          sqlite3VdbeAddOp3(v, OP_And, r3, r4, r4);



        }

      }
      addrIf = sqlite3VdbeAddOp1(v, OP_If, r4);
      if( destIfNull!=destIfFalse ){
        sqlite3VdbeAddOp2(v, OP_IfNot, r4, sqlite3VdbeCurrentAddr(v)+2);







        sqlite3VdbeAddOp2(v, OP_Integer, 1, regNull);
      }
      sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrNext+1);
      if( destIfNull!=destIfFalse ){
        sqlite3VdbeAddOp2(v, OP_If, regNull, destIfNull);
      }
      sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
      sqlite3VdbeChangeP2(v, addrIf, sqlite3VdbeCurrentAddr(v));
      sqlite3ReleaseTempReg(pParse, regNull);
      sqlite3ReleaseTempReg(pParse, r2);
      sqlite3ReleaseTempReg(pParse, r3);
      sqlite3ReleaseTempReg(pParse, r4);
    }else{
      /* In this case, the RHS is an index b-tree.
      */
      sqlite3VdbeAddOp4(v, OP_Affinity, r1, nVector, 0, zAff, nVector);
  
      /* If the set membership test fails, then the result of the 
      ** "x IN (...)" expression must be either 0 or NULL. If the set
      ** contains no NULL values, then the result is 0. If the set 
      ** contains one or more NULL values, then the result of the
      ** expression is also NULL.
      */
      assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
      if( rRhsHasNull==0 ){
        /* This branch runs if it is known at compile time that the RHS
        ** cannot contain NULL values. This happens as the result
        ** of a "NOT NULL" constraint in the database schema.
        **
        ** Also run this branch if NULL is equivalent to FALSE
        ** for this particular IN operator.
        */
        sqlite3VdbeAddOp4Int(
            v, OP_NotFound, pExpr->iTable, destIfFalse, r1, nVector
        );
        VdbeCoverage(v);
      }else{
        /* In this branch, the RHS of the IN might contain a NULL and
        ** the presence of a NULL on the RHS makes a difference in the
        ** outcome.
        */
        int addr1;
  
        /* First check to see if the LHS is contained in the RHS.  If so,
        ** then the answer is TRUE the presence of NULLs in the RHS does
        ** not matter.  If the LHS is not contained in the RHS, then the
        ** answer is NULL if the RHS contains NULLs and the answer is
        ** FALSE if the RHS is NULL-free.
        */
        addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
................................................................................
*/
int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
  Vdbe *v = pParse->pVdbe;  /* The VM under construction */
  int op;                   /* The opcode being coded */
  int inReg = target;       /* Results stored in register inReg */
  int regFree1 = 0;         /* If non-zero free this temporary register */
  int regFree2 = 0;         /* If non-zero free this temporary register */
  int r1, r2, r3, r4;       /* Various register numbers */
  sqlite3 *db = pParse->db; /* The database connection */
  Expr tempX;               /* Temporary expression node */
  int p5 = 0;

  assert( target>0 && target<=pParse->nMem );
  if( v==0 ){
    assert( pParse->db->mallocFailed );
................................................................................
    **
    ** X is stored in pExpr->pLeft.
    ** Y is stored in pExpr->pList->a[0].pExpr.
    ** Z is stored in pExpr->pList->a[1].pExpr.
    */
    case TK_BETWEEN: {
      exprCodeBetween(pParse, pExpr, target, 0, 0);
#if 0
      Expr *pLeft = pExpr->pLeft;
      struct ExprList_item *pLItem = pExpr->x.pList->a;
      Expr *pRight = pLItem->pExpr;

      r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
      testcase( regFree1==0 );
      testcase( regFree2==0 );
      r3 = sqlite3GetTempReg(pParse);
      r4 = sqlite3GetTempReg(pParse);
      codeCompare(pParse, pLeft, pRight, OP_Ge,
                  r1, r2, r3, SQLITE_STOREP2);  VdbeCoverage(v);
      pLItem++;
      pRight = pLItem->pExpr;
      sqlite3ReleaseTempReg(pParse, regFree2);
      r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
      testcase( regFree2==0 );
      codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
      VdbeCoverage(v);
      sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
      sqlite3ReleaseTempReg(pParse, r3);
      sqlite3ReleaseTempReg(pParse, r4);
#endif
      break;
    }
    case TK_SPAN:
    case TK_COLLATE: 
    case TK_UPLUS: {
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
      break;
................................................................................
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) )     return;  /* Existence of VDBE checked by caller */
  if( NEVER(pExpr==0) ) return;  /* No way this can happen */
  op = pExpr->op;
  switch( op | (pExpr->pLeft ? (pExpr->pLeft->flags & EP_Vector) : 0)){
    case TK_AND: {
      int d2 = sqlite3VdbeMakeLabel(v);
      testcase( jumpIfNull==0 );
      sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
      sqlite3ExprCachePush(pParse);
      sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
      sqlite3VdbeResolveLabel(v, d2);
................................................................................
      /* Fall thru */
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:
    case TK_NE:
    case TK_EQ: {

      testcase( jumpIfNull==0 );
      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
                  r1, r2, dest, jumpIfNull);
      assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
      assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
................................................................................
      sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
      sqlite3VdbeGoto(v, dest);
      sqlite3VdbeResolveLabel(v, destIfFalse);
      break;
    }
#endif
    default: {

      if( exprAlwaysTrue(pExpr) ){
        sqlite3VdbeGoto(v, dest);
      }else if( exprAlwaysFalse(pExpr) ){
        /* No-op */
      }else{
        r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
        sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0);







|







 







|
<
<




<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
<
|







 







|
|
<





|
|
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>






>







 







>
>
>
>
>
>
>
|
<
>







 







|
<


>
>
>
>
>
|
<
<
<
<
>
|
|

<
|
>
|
>
>
>
|
>
|
|
|
>
|
|

|
|
|
<
|
>
>
>

>
|
<
<
<
>
>
>
>
>
>
>
|
|
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
|

|
|


|
<










|







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|







 







>







 







>







1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
....
1755
1756
1757
1758
1759
1760
1761
1762


1763
1764
1765
1766



1767
1768
1769
1770
1771
1772
1773
....
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921

1922
1923
1924
1925
1926
1927
1928
1929
....
2003
2004
2005
2006
2007
2008
2009
2010
2011

2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
....
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
....
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
....
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528

2529
2530
2531
2532
2533
2534
2535
2536
....
2539
2540
2541
2542
2543
2544
2545
2546

2547
2548
2549
2550
2551
2552
2553
2554




2555
2556
2557
2558

2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576

2577
2578
2579
2580
2581
2582
2583



2584
2585
2586
2587
2588
2589
2590
2591
2592



2593










2594







2595
2596
2597
2598
2599
2600
2601

2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
....
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
....
3438
3439
3440
3441
3442
3443
3444
























3445
3446
3447
3448
3449
3450
3451
....
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
....
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
....
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
** used in a context in which there is no difference between a result
** of 0 and one of NULL. For example:
**
**     ... WHERE (?,?) IN (SELECT ...)
**
*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(Expr *pX){
  Select *p;
  SrcList *pSrc;
  ExprList *pEList;
  Table *pTab;
  int i;
  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
................................................................................
  if( pSrc->a[0].pSelect ) return 0;     /* FROM is not a subquery or view */
  pTab = pSrc->a[0].pTab;
  assert( pTab!=0 );
  assert( pTab->pSelect==0 );            /* FROM clause is not a view */
  if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
  pEList = p->pEList;

  /* All SELECT results must be columns. */


  for(i=0; i<pEList->nExpr; i++){
    Expr *pRes = pEList->a[i].pExpr;
    if( pRes->op!=TK_COLUMN ) return 0;
    assert( pRes->iTable==pSrc->a[0].iCursor );  /* Not a correlated subquery */



  }
  return p;
}
#endif /* SQLITE_OMIT_SUBQUERY */

/*
** Code an OP_Once instruction and allocate space for its flag. Return the 
................................................................................
  int eType = 0;                        /* Type of RHS table. IN_INDEX_* */
  int iTab = pParse->nTab++;            /* Cursor of the RHS table */
  int mustBeUnique;                     /* True if RHS must be unique */
  Vdbe *v = sqlite3GetVdbe(pParse);     /* Virtual machine being coded */

  assert( pX->op==TK_IN );
  mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;

  /* If the RHS of this IN(...) operator is a SELECT, and if it matters 
  ** whether or not the SELECT result contains NULL values, check whether
  ** or not NULL is actuall possible (it may not be, for example, due 
  ** to NOT NULL constraints in the schema). If no NULL values are possible,
  ** set prRhsHasNull to 0 before continuing.
  */
  if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
    int i;
    ExprList *pEList = pX->x.pSelect->pEList;
    for(i=0; i<pEList->nExpr; i++){
      if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break;
    }
    if( i==pEList->nExpr ){
      prRhsHasNull = 0;
    }
  }

  /* Check to see if an existing table or index can be used to
  ** satisfy the query.  This is preferable to generating a new 
  ** ephemeral table.  */

  if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
    sqlite3 *db = pParse->db;              /* Database connection */
    Table *pTab;                           /* Table <table>. */
    i16 iDb;                               /* Database idx for pTab */
    ExprList *pEList = p->pEList;
    int nExpr = pEList->nExpr;

    assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
................................................................................
          int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
          sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
          sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
          VdbeComment((v, "%s", pIdx->zName));
          assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
          eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];

          if( prRhsHasNull ){
            *prRhsHasNull = ++pParse->nMem;

#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
            i64 mask = (1<<nExpr)-1;
            sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, 
                iTab, 0, 0, (u8*)&mask, P4_INT64);
#endif
            if( nExpr==1 ){
              sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
            }
          }
          sqlite3VdbeJumpHere(v, iAddr);
        }
      }
    }
  }

................................................................................
    sqlite3VdbeJumpHere(v, jmpIfDynamic);
  }
  sqlite3ExprCachePop(pParse);

  return rReg;
}
#endif /* SQLITE_OMIT_SUBQUERY */

#ifndef SQLITE_OMIT_SUBQUERY
/*
** Expr pIn is an IN(...) expression. This function checks that the 
** sub-select on the RHS of the IN() operator has the same number of 
** columns as the vector on the LHS. Or, if the RHS of the IN() is not 
** a sub-query, that the LHS is a vector of size 1.
*/
int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
  int nVector = sqlite3ExprVectorSize(pIn->pLeft);
  if( (pIn->flags & EP_xIsSelect) ){
    if( nVector!=pIn->x.pSelect->pEList->nExpr ){
      sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
      return 1;
    }
  }else if( nVector!=1 ){
    if( (pIn->pLeft->flags & EP_xIsSelect) ){
      sqlite3SubselectError(pParse, nVector, 1);
    }else{
      sqlite3ErrorMsg(pParse, "invalid use of row value");
    }
    return 1;
  }
  return 0;
}
#endif

#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate code for an IN expression.
**
**      x IN (SELECT ...)
**      x IN (value, value, ...)
................................................................................
  int *aiMap = 0;       /* Map from vector field to index column */
  char *zAff = 0;       /* Affinity string for comparisons */
  int nVector;          /* Size of vectors for this IN(...) op */
  int regSelect = 0;
  Expr *pLeft = pExpr->pLeft;
  int i;

  if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
  nVector = sqlite3ExprVectorSize(pExpr->pLeft);
  aiMap = (int*)sqlite3DbMallocZero(
      pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
  );
  if( !aiMap ) return;
  zAff = (char*)&aiMap[nVector];


  /* Attempt to compute the RHS. After this step, if anything other than
  ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable 
  ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
  ** the RHS has not yet been coded.  */
  v = pParse->pVdbe;
  assert( v!=0 );       /* OOM detected prior to this routine */
................................................................................
      sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfFalse);
    }
    sqlite3VdbeResolveLabel(v, labelOk);
    sqlite3ReleaseTempReg(pParse, regCkNull);
  }else{
  
    /* If any value on the LHS is NULL, the result of the IN(...) operator
    ** must be either false or NULL. If these two are handled identically,
    ** test the LHS for NULLs and jump directly to destIfNull if any are
    ** found. 
    **
    ** Otherwise, if NULL and false are handled differently, and the
    ** IN(...) operation is not a vector operation, and the LHS of the
    ** operator is NULL, then the result is false if the index is 

    ** completely empty, or NULL otherwise.  */
    if( destIfNull==destIfFalse ){
      for(i=0; i<nVector; i++){
        Expr *p = exprVectorField(pExpr->pLeft, i);
        if( sqlite3ExprCanBeNull(p) ){
          sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull);
        }
      }
................................................................................
      sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
      VdbeCoverage(v);
      sqlite3VdbeGoto(v, destIfNull);
      sqlite3VdbeJumpHere(v, addr1);
    }
  
    if( eType==IN_INDEX_ROWID ){
      /* In this case, the RHS is the ROWID of table b-tree */

      sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1);
      VdbeCoverage(v);
    }else{
      /* In this case, the RHS is an index b-tree. Apply the comparison
      ** affinities to each value on the LHS of the operator.  */
      sqlite3VdbeAddOp4(v, OP_Affinity, r1, nVector, 0, zAff, nVector);
      
      if( nVector>1 && destIfNull!=destIfFalse ){




        int iIdx = pExpr->iTable;
        int addr;
        int addrNext;


        /* Search the index for the key. */
        addr = sqlite3VdbeAddOp4Int(v, OP_Found, iIdx, 0, r1, nVector);

        /* At this point the specified key is not present in the index, 
        ** so the result of the IN(..) operator must be either NULL or
        ** 0. The vdbe code generated below figures out which.  */
        addrNext = 1+sqlite3VdbeAddOp2(v, OP_Rewind, iIdx, destIfFalse);

        for(i=0; i<nVector; i++){
          Expr *p;
          CollSeq *pColl;
          int r2 = sqlite3GetTempReg(pParse);
          p = exprVectorField(pLeft, i);
          pColl = sqlite3ExprCollSeq(pParse, p);

          sqlite3VdbeAddOp3(v, OP_Column, iIdx, i, r2);
          sqlite3VdbeAddOp4(v, OP_Eq, r1+i, 0, r2, (void*)pColl,P4_COLLSEQ);
          sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);

          sqlite3VdbeAddOp2(v, OP_Next, iIdx, addrNext);
          sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
          sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-3);
          sqlite3ReleaseTempReg(pParse, r2);
        }
        sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);




        /* The key was found in the index. If it contains any NULL values,
        ** then the result of the IN(...) operator is NULL. Otherwise, the
        ** result is 1.  */
        sqlite3VdbeJumpHere(v, addr);
        for(i=0; i<nVector; i++){
          Expr *p = exprVectorField(pExpr->pLeft, i);
          if( sqlite3ExprCanBeNull(p) ){
            sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull);
          }



        }


















      }else if( rRhsHasNull==0 ){
        /* This branch runs if it is known at compile time that the RHS
        ** cannot contain NULL values. This happens as a result
        ** of "NOT NULL" constraints in the database schema.
        **
        ** Also run this branch if NULL is equivalent to FALSE
        ** for this particular IN operator.  */

        sqlite3VdbeAddOp4Int(
            v, OP_NotFound, pExpr->iTable, destIfFalse, r1, nVector
        );
        VdbeCoverage(v);
      }else{
        /* In this branch, the RHS of the IN might contain a NULL and
        ** the presence of a NULL on the RHS makes a difference in the
        ** outcome.
        */
        int addr1;

        /* First check to see if the LHS is contained in the RHS.  If so,
        ** then the answer is TRUE the presence of NULLs in the RHS does
        ** not matter.  If the LHS is not contained in the RHS, then the
        ** answer is NULL if the RHS contains NULLs and the answer is
        ** FALSE if the RHS is NULL-free.
        */
        addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
................................................................................
*/
int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
  Vdbe *v = pParse->pVdbe;  /* The VM under construction */
  int op;                   /* The opcode being coded */
  int inReg = target;       /* Results stored in register inReg */
  int regFree1 = 0;         /* If non-zero free this temporary register */
  int regFree2 = 0;         /* If non-zero free this temporary register */
  int r1, r2;               /* Various register numbers */
  sqlite3 *db = pParse->db; /* The database connection */
  Expr tempX;               /* Temporary expression node */
  int p5 = 0;

  assert( target>0 && target<=pParse->nMem );
  if( v==0 ){
    assert( pParse->db->mallocFailed );
................................................................................
    **
    ** X is stored in pExpr->pLeft.
    ** Y is stored in pExpr->pList->a[0].pExpr.
    ** Z is stored in pExpr->pList->a[1].pExpr.
    */
    case TK_BETWEEN: {
      exprCodeBetween(pParse, pExpr, target, 0, 0);
























      break;
    }
    case TK_SPAN:
    case TK_COLLATE: 
    case TK_UPLUS: {
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
      break;
................................................................................
  int regFree2 = 0;
  int r1, r2;

  assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
  if( NEVER(v==0) )     return;  /* Existence of VDBE checked by caller */
  if( NEVER(pExpr==0) ) return;  /* No way this can happen */
  op = pExpr->op;
  switch( op ){
    case TK_AND: {
      int d2 = sqlite3VdbeMakeLabel(v);
      testcase( jumpIfNull==0 );
      sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
      sqlite3ExprCachePush(pParse);
      sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
      sqlite3VdbeResolveLabel(v, d2);
................................................................................
      /* Fall thru */
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:
    case TK_NE:
    case TK_EQ: {
      if( pExpr->pLeft->flags & EP_Vector ) goto default_expr;
      testcase( jumpIfNull==0 );
      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
      codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
                  r1, r2, dest, jumpIfNull);
      assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
      assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
................................................................................
      sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
      sqlite3VdbeGoto(v, dest);
      sqlite3VdbeResolveLabel(v, destIfFalse);
      break;
    }
#endif
    default: {
    default_expr:
      if( exprAlwaysTrue(pExpr) ){
        sqlite3VdbeGoto(v, dest);
      }else if( exprAlwaysFalse(pExpr) ){
        /* No-op */
      }else{
        r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
        sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0);

Changes to src/whereexpr.c.

930
931
932
933
934
935
936

937
938
939
940
941
942
943
  pMaskSet = &pWInfo->sMaskSet;
  pExpr = pTerm->pExpr;
  assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
  prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
  op = pExpr->op;
  if( op==TK_IN ){
    assert( pExpr->pRight==0 );

    if( ExprHasProperty(pExpr, EP_xIsSelect) ){
      pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
    }else{
      pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
    }
  }else if( op==TK_ISNULL ){
    pTerm->prereqRight = 0;







>







930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  pMaskSet = &pWInfo->sMaskSet;
  pExpr = pTerm->pExpr;
  assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
  prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
  op = pExpr->op;
  if( op==TK_IN ){
    assert( pExpr->pRight==0 );
    if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
    if( ExprHasProperty(pExpr, EP_xIsSelect) ){
      pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
    }else{
      pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
    }
  }else if( op==TK_ISNULL ){
    pTerm->prereqRight = 0;

Added test/rowvalue4.test.

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 2016 July 29
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is syntax errors involving row-value constructors
# and sub-selects that return multiple arguments.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix rowvalue4

do_execsql_test 0 {
  CREATE TABLE t1(a, b, c);
  CREATE INDEX t1bac ON t1(b, a, c);
}

foreach {tn e} {
  1 "(1, 2, 3)"
  2 "1 + (1, 2)"
  3 "(1,2,3) == (1, 2)"
} {
  do_catchsql_test 1.$tn "SELECT $e" {1 {invalid use of row value}}
}

foreach {tn s error} {
  1 "SELECT * FROM t1 WHERE a = (1, 2)"       {invalid use of row value}
  2 "SELECT * FROM t1 WHERE b = (1, 2)"       {invalid use of row value}
  3 "SELECT * FROM t1 WHERE NOT (b = (1, 2))" {invalid use of row value}
  4 "SELECT * FROM t1 LIMIT (1, 2)"           {invalid use of row value}
  5 "SELECT (a, b) IN (SELECT * FROM t1) FROM t1" 
                             {sub-select returns 3 columns - expected 2}

  6 "SELECT * FROM t1 WHERE (a, b) IN (SELECT * FROM t1)" 
                             {sub-select returns 3 columns - expected 2}
} {
  do_catchsql_test 2.$tn "$s" [list 1 $error]
}

finish_test