SQLite

Check-in [1f4dba87da]
Login

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

Overview
Comment:Fix a problem with IN(...) constraints where the LHS is a sub-select that is an aggregate query.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | rowvalue
Files: files | file ages | folders
SHA1: 1f4dba87da4a44ad26223ad965731164c0d9bad9
User & Date: dan 2016-08-01 16:37:43.292
Context
2016-08-01
20:14
Fix a problem with vector range constraints involving the rowid column. And other issues. (check-in: 3ef75d45eb user: dan tags: rowvalue)
16:37
Fix a problem with IN(...) constraints where the LHS is a sub-select that is an aggregate query. (check-in: 1f4dba87da user: dan tags: rowvalue)
2016-07-30
21:02
Fix problems with vector == comparisons and NULL values. (check-in: 059d0d0535 user: dan tags: rowvalue)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
304
305
306
307
308
309
310









311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338

339
340
341
342

343
344

345
346
347
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

371




372




373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392


393
394
395
396
397
398
399
400
401
402
403
404
  p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
  p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
  addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
                           (void*)p4, P4_COLLSEQ);
  sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
  return addr;
}










/*
** If the expression passed as the only argument is of type TK_VECTOR 
** return the number of expressions in the vector. Or, if the expression
** is a sub-select, return the number of columns in the sub-select. For
** any other type of expression, return 1.
*/
int sqlite3ExprVectorSize(Expr *pExpr){
  if( sqlite3ExprIsVector(pExpr)==0 ) return 1;
  if( pExpr->flags & EP_xIsSelect ){
    return pExpr->x.pSelect->pEList->nExpr;
  }
  return pExpr->x.pList->nExpr;
}

/*
** Return true if expression pExpr is a vector, or false otherwise.
*/
int sqlite3ExprIsVector(Expr *pExpr){
  return (
      pExpr->op==TK_VECTOR 
   || (pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1)
  );
}

/*
** If the expression passed as the first argument is a TK_VECTOR, return
** a pointer to the i'th field of the vector. Or, if the first argument

** points to a sub-select, return a pointer to the i'th returned column 
** value. Otherwise, return a copy of the first argument.
*/
static Expr *exprVectorField(Expr *pVector, int i){

  if( sqlite3ExprIsVector(pVector)==0 ){
    assert( i==0 );

    return pVector;
  }else if( pVector->flags & EP_xIsSelect ){
    return pVector->x.pSelect->pEList->a[i].pExpr;
  }

  return pVector->x.pList->a[i].pExpr;
}

/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
** it. Return the register in which the result is stored (or, if the 
** sub-select returns more than one column, the first in an array
** of registers in which the result is stored).
**
** If pExpr is not a TK_SELECT expression, return 0.
*/
static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
  int reg = 0;
  if( pExpr->op==TK_SELECT ){
    reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
  }
  return reg;
}

/*
** Argument pVector points to a vector expression - either a TK_VECTOR
** or TK_SELECT that returns more than one column. This function generates

** code to evaluate expression iElem of the vector. The number of the




** register containing the result is returned. 




**
** Before returning, output parameter (*ppExpr) is set to point to the
** Expr object corresponding to element iElem of the vector.
**
** If pVector is a TK_SELECT expression, then argument regSelect is 
** passed the first in an array of registers that contain the results
** of the sub-select. 
**
** If output parameter (*pRegFree) is set to a non-zero value by this
** function, it is the value of a temporary register that should be
** freed by the caller.
*/
static int exprVectorRegister(
  Parse *pParse,                  /* Parse context */
  Expr *pVector,                  /* Vector to extract element from */
  int iElem,                      /* Element to extract from pVector */
  int regSelect,                  /* First in array of registers */
  Expr **ppExpr,                  /* OUT: Expression element */
  int *pRegFree                   /* OUT: Temp register to free */
){


  if( regSelect ){
    *ppExpr = pVector->x.pSelect->pEList->a[iElem].pExpr;
     return regSelect+iElem;
  }
  *ppExpr = pVector->x.pList->a[iElem].pExpr;
  return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
}

/*
** Expression pExpr is a comparison between two vector values. Compute
** the result of the comparison and write it to register dest.
*/







>
>
>
>
>
>
>
>
>















<
<
<
<
<
<
<
<
<
<



>
|
|


>
|
<
>
|
|
|
|
>
|




















|
>
|
>
>
>
>
|
>
>
>
>



<
<
<
<
<
<
<
<




|




>
>

|
|

|







304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334










335
336
337
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386








387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
  p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
  addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
                           (void*)p4, P4_COLLSEQ);
  sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
  return addr;
}

/*
** Return true if expression pExpr is a vector, or false otherwise.
*/
int sqlite3ExprIsVector(Expr *pExpr){
  return ( (pExpr->op==TK_VECTOR)
        || (pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1)
  );
}

/*
** If the expression passed as the only argument is of type TK_VECTOR 
** return the number of expressions in the vector. Or, if the expression
** is a sub-select, return the number of columns in the sub-select. For
** any other type of expression, return 1.
*/
int sqlite3ExprVectorSize(Expr *pExpr){
  if( sqlite3ExprIsVector(pExpr)==0 ) return 1;
  if( pExpr->flags & EP_xIsSelect ){
    return pExpr->x.pSelect->pEList->nExpr;
  }
  return pExpr->x.pList->nExpr;
}











/*
** If the expression passed as the first argument is a TK_VECTOR, return
** a pointer to the i'th field of the vector. Or, if the first argument
** points to a sub-select that returns more than one column, return a 
** pointer to the i'th returned column value. Otherwise, return a copy 
** of the first argument.
*/
static Expr *exprVectorField(Expr *pVector, int i){
  assert( i<sqlite3ExprVectorSize(pVector) );
  if( sqlite3ExprIsVector(pVector) ){

    if( pVector->op==TK_SELECT ){
      return pVector->x.pSelect->pEList->a[i].pExpr;
    }else{
      return pVector->x.pList->a[i].pExpr;
    }
  }
  return pVector;
}

/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
** it. Return the register in which the result is stored (or, if the 
** sub-select returns more than one column, the first in an array
** of registers in which the result is stored).
**
** If pExpr is not a TK_SELECT expression, return 0.
*/
static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
  int reg = 0;
  if( pExpr->op==TK_SELECT ){
    reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
  }
  return reg;
}

/*
** Argument pVector points to a vector expression - either a TK_VECTOR
** or TK_SELECT that returns more than one column. This function returns
** the register number of a register that contains the value of
** element iField of the vector.
**
** If pVector is a TK_SELECT expression, then code for it must have 
** already been generated using the exprCodeSubselect() routine. In this
** case parameter regSelect should be the first in an array of registers
** containing the results of the sub-select. 
**
** If pVector is of type TK_VECTOR, then code for the requested field
** is generated. In this case (*pRegFree) may be set to the number of
** a temporary register to be freed by the caller before returning.
**
** Before returning, output parameter (*ppExpr) is set to point to the
** Expr object corresponding to element iElem of the vector.








*/
static int exprVectorRegister(
  Parse *pParse,                  /* Parse context */
  Expr *pVector,                  /* Vector to extract element from */
  int iField,                     /* Field to extract from pVector */
  int regSelect,                  /* First in array of registers */
  Expr **ppExpr,                  /* OUT: Expression element */
  int *pRegFree                   /* OUT: Temp register to free */
){
  assert( pVector->op==TK_VECTOR || pVector->op==TK_SELECT );
  assert( (pVector->op==TK_VECTOR)==(regSelect==0) );
  if( regSelect ){
    *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr;
     return regSelect+iField;
  }
  *ppExpr = pVector->x.pList->a[iField].pExpr;
  return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
}

/*
** Expression pExpr is a comparison between two vector values. Compute
** the result of the comparison and write it to register dest.
*/
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

  /* Check that both sides of the comparison are vectors, and that
  ** both are the same length.  */
  if( nLeft!=nRight ){
    sqlite3ErrorMsg(pParse, "invalid use of row value");
  }else{
    int p5 = (pExpr->op==TK_IS || pExpr->op==TK_ISNOT) ? SQLITE_NULLEQ : 0;
    int opCmp;
    int i;
    int p3 = 0;
    int p4 = 0;
    int regLeft = 0;
    int regRight = 0;
    int regTmp = 0;

    assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
         || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
         || pExpr->op==TK_LT || pExpr->op==TK_GT 







<

<
<







417
418
419
420
421
422
423

424


425
426
427
428
429
430
431

  /* Check that both sides of the comparison are vectors, and that
  ** both are the same length.  */
  if( nLeft!=nRight ){
    sqlite3ErrorMsg(pParse, "invalid use of row value");
  }else{
    int p5 = (pExpr->op==TK_IS || pExpr->op==TK_ISNOT) ? SQLITE_NULLEQ : 0;

    int i;


    int regLeft = 0;
    int regRight = 0;
    int regTmp = 0;

    assert( pExpr->op==TK_EQ || pExpr->op==TK_NE 
         || pExpr->op==TK_IS || pExpr->op==TK_ISNOT 
         || pExpr->op==TK_LT || pExpr->op==TK_GT 
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793

/*
** pX is the RHS of an IN operator.  If pX is a SELECT statement 
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement.  If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
** table, then return NULL.
** 
** If parameter bNullSensitive is 0, then this operation will be
** 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;







<
<
<
<
<
<
<







1775
1776
1777
1778
1779
1780
1781







1782
1783
1784
1785
1786
1787
1788

/*
** pX is the RHS of an IN operator.  If pX is a SELECT statement 
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement.  If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
** table, then return NULL.







*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(Expr *pX){
  Select *p;
  SrcList *pSrc;
  ExprList *pEList;
  Table *pTab;
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
  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 ){







|

|
<







1948
1949
1950
1951
1952
1953
1954
1955
1956
1957

1958
1959
1960
1961
1962
1963
1964
  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 actually 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 ){
Changes to src/select.c.
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
  r1 = sqlite3GetTempReg(pParse);
  sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
  sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
  sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
  sqlite3ReleaseTempReg(pParse, r1);
}

#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate an error message when a SELECT is used within a subexpression
** (example:  "a IN (SELECT * FROM table)") but it has more than 1 result
** column.  We do this in a subroutine because the error used to occur
** in multiple places.  (The error only occurs in one place now, but we
** retain the subroutine to minimize code disruption.)
*/
static int checkForMultiColumnSelectError(
  Parse *pParse,       /* Parse context. */
  SelectDest *pDest,   /* Destination of SELECT results */
  int nExpr            /* Number of result columns returned by SELECT */
){
  int eDest = pDest->eDest;
  if( 0 && nExpr>1 && eDest==SRT_Set ){
    sqlite3ErrorMsg(pParse, "only a single result allowed for "
       "a SELECT that is part of an expression");
    return 1;
  }else{
    return 0;
  }
}
#endif

/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
** If srcTab is negative, then the pEList expressions
** are evaluated in order to get the data for this row.  If srcTab is
** zero or more, then data is pulled from srcTab and pEList is used only 







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







655
656
657
658
659
660
661
























662
663
664
665
666
667
668
  r1 = sqlite3GetTempReg(pParse);
  sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
  sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
  sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
  sqlite3ReleaseTempReg(pParse, r1);
}

























/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
** If srcTab is negative, then the pEList expressions
** are evaluated in order to get the data for this row.  If srcTab is
** zero or more, then data is pulled from srcTab and pEList is used only 
915
916
917
918
919
920
921
922
923
924
925
926
927

928
929
930
931
932
933
934
935
    case SRT_Exists: {
      sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
      /* The LIMIT clause will terminate the loop for us */
      break;
    }

    /* If this is a scalar select that is part of an expression, then
    ** store the results in the appropriate memory cell and break out
    ** of the scan loop.
    */
    case SRT_Mem: {
      assert( nResultCol==pDest->nSdst );
      if( pSort ){

        pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
      }else{
        assert( regResult==iParm );
        /* The LIMIT clause will jump out of the loop for us */
      }
      break;
    }
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */







|
|




>
|







891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
    case SRT_Exists: {
      sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
      /* The LIMIT clause will terminate the loop for us */
      break;
    }

    /* If this is a scalar select that is part of an expression, then
    ** store the results in the appropriate memory cell or array of 
    ** memory cells and break out of the scan loop.
    */
    case SRT_Mem: {
      assert( nResultCol==pDest->nSdst );
      if( pSort ){
        pushOntoSorter(
            pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
      }else{
        assert( regResult==iParm );
        /* The LIMIT clause will jump out of the loop for us */
      }
      break;
    }
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
  assert( p->pEList!=0 );
  isAgg = (p->selFlags & SF_Aggregate)!=0;
#if SELECTTRACE_ENABLED
  if( sqlite3SelectTrace & 0x100 ){
    SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }
#endif


  /* If writing to memory or generating a set
  ** only a single column may be output.
  */
#ifndef SQLITE_OMIT_SUBQUERY
  if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
    goto select_end;
  }
#endif

  /* Try to flatten subqueries in the FROM clause up into the main query
  */
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
  for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    struct SrcList_item *pItem = &pTabList->a[i];







<
<
<
<
<
<
<
<
<
<







4865
4866
4867
4868
4869
4870
4871










4872
4873
4874
4875
4876
4877
4878
  assert( p->pEList!=0 );
  isAgg = (p->selFlags & SF_Aggregate)!=0;
#if SELECTTRACE_ENABLED
  if( sqlite3SelectTrace & 0x100 ){
    SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
    sqlite3TreeViewSelect(0, p, 0);
  }










#endif

  /* Try to flatten subqueries in the FROM clause up into the main query
  */
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
  for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    struct SrcList_item *pItem = &pTabList->a[i];
Changes to src/whereexpr.c.
868
869
870
871
872
873
874











875
876

877
878
879
880
881
882
883
884
885
886
887
888
        return 1;
      }
    }
  }
  return 0;
}












static Expr *exprVectorExpr(Parse *pParse, Expr *p, int iField){
  Expr *pRet;

  if( p->flags & EP_xIsSelect ){
    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, p, 0, 0);
    if( pRet ) pRet->iColumn = iField;
  }else{
    pRet = sqlite3ExprDup(pParse->db, p->x.pList->a[iField].pExpr, 0);
  }
  return pRet;
}

/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in.  The job of this routine is to analyze the







>
>
>
>
>
>
>
>
>
>
>
|

>
|
|


|







868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
        return 1;
      }
    }
  }
  return 0;
}

/*
** The expression passed as the second argument is a vector (either a 
** TK_VECTOR node or a TK_SELECT that returns more than one column). This
** function returns a pointer to a new expression object representing
** field iField of the vector.
**
** If pVector is of type TK_VECTOR, the returned object is just a copy of
** the iField'th element of the vector. Or, if pVector is of type TK_SELECT,
** the return value points to a new expression object of type 
** TK_SELECT_COLUMN.
*/
static Expr *exprExtractVectorField(Parse *pParse, Expr *pVector, int iField){
  Expr *pRet;
  assert( sqlite3ExprIsVector(pVector) );
  if( pVector->flags & EP_xIsSelect ){
    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, pVector, 0, 0);
    if( pRet ) pRet->iColumn = iField;
  }else{
    pRet = sqlite3ExprDup(pParse->db, pVector->x.pList->a[iField].pExpr, 0);
  }
  return pRet;
}

/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in.  The job of this routine is to analyze the
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
  )){
    int nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
    if( nLeft==sqlite3ExprVectorSize(pExpr->pRight) ){
      int i;
      for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
        int idxNew;
        Expr *pNew;
        Expr *pLeft = exprVectorExpr(pParse, pExpr->pLeft, i);
        Expr *pRight = exprVectorExpr(pParse, pExpr->pRight, i);

        pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0);
        idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
        exprAnalyze(pSrc, pWC, idxNew);
        markTermAsChild(pWC, idxNew, idxTerm);
      }
    }







|
|







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  )){
    int nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
    if( nLeft==sqlite3ExprVectorSize(pExpr->pRight) ){
      int i;
      for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
        int idxNew;
        Expr *pNew;
        Expr *pLeft = exprExtractVectorField(pParse, pExpr->pLeft, i);
        Expr *pRight = exprExtractVectorField(pParse, pExpr->pRight, i);

        pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0);
        idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
        exprAnalyze(pSrc, pWC, idxNew);
        markTermAsChild(pWC, idxNew, idxTerm);
      }
    }
Changes to test/rowvalue.test.
190
191
192
193
194
195
196






197
198
199
200
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}"

} {
  do_eqp_test 7.$tn.1 $sql $eqp
  do_execsql_test 7.$tn.2 $sql $res
}









finish_test








>
>
>
>
>
>




190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}"

} {
  do_eqp_test 7.$tn.1 $sql $eqp
  do_execsql_test 7.$tn.2 $sql $res
}

do_execsql_test 8.0 {
  CREATE TABLE j1(a);
}
do_execsql_test 8.1 {
  SELECT * FROM j1 WHERE (select min(a) FROM j1) IN (?, ?, ?)
}


finish_test