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

Overview
Comment:Remove some rowid-related dead code from where.c. Fix other code issues in the same file.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4856f089442ac5fb07f3fc2544a8c08cdfdb4f0c
User & Date: dan 2013-07-29 18:07:05.357
Context
2013-07-29
19:31
Remove the unused OP_InsertInt opcode from the VDBE. check-in: 3e371e1a44 user: drh tags: trunk
18:07
Remove some rowid-related dead code from where.c. Fix other code issues in the same file. check-in: 4856f08944 user: dan tags: trunk
17:57
Code clarifications: Do not overload the "nField" variable (in the OP_MakeRecord opcode) to mean something other than the number of fields to be encoded. check-in: 20962f1a72 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
1422
1423
1424
1425
1426
1427
1428
1429

1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444



1445
1446

1447


1448
1449













1450
1451
1452
1453
1454
1455
1456
** all members of the RHS set, skipping duplicates.
**
** A cursor is opened on the b-tree object that the RHS of the IN operator
** and pX->iTable is set to the index of that cursor.
**
** The returned value of this function indicates the b-tree type, as follows:
**
**   IN_INDEX_ROWID      - The cursor was opened on a database table.

**   IN_INDEX_INDEX_ASC  - The cursor was opened on an ascending index.
**   IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
**   IN_INDEX_EPH        - The cursor was opened on a specially created and
**                         populated epheremal table.
**
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
**
**     SELECT <column> FROM <table>
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephermeral table instead of an
** existing table.  
**



** If the prNotFound parameter is 0, then the b-tree will be used to iterate
** through the set members, skipping any duplicates. In this case an

** epheremal table must be used unless the selected <column> is guaranteed


** to be unique - either because it is an INTEGER PRIMARY KEY or it
** has a UNIQUE constraint or UNIQUE index.













**
** If the prNotFound parameter is not 0, then the b-tree will be used 
** for fast set membership tests. In this case an epheremal table must 
** be used unless <column> is an INTEGER PRIMARY KEY or an index can 
** be found with <column> as its left-most column.
**
** When the b-tree is being used for membership tests, the calling function







|
>















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







1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455

1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
** all members of the RHS set, skipping duplicates.
**
** A cursor is opened on the b-tree object that the RHS of the IN operator
** and pX->iTable is set to the index of that cursor.
**
** The returned value of this function indicates the b-tree type, as follows:
**
**   IN_INDEX_ROWID      - The cursor was opened on the PK index of a
**                         table with an implicit integer primary key.
**   IN_INDEX_INDEX_ASC  - The cursor was opened on an ascending index.
**   IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
**   IN_INDEX_EPH        - The cursor was opened on a specially created and
**                         populated epheremal table.
**
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
**
**     SELECT <column> FROM <table>
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephermeral table instead of an
** existing table.  
**
**
** ITERATING THROUGH SET MEMBERS
** 
**   If the prNotFound parameter is 0, then the b-tree will be used to 
**   iterate through the set members, skipping any duplicates. In this
**   case the piCov parameter is always non-zero. An index on column 
**   <column> of <table> is used in this case if:
**
**     1. The index guarantees the column is unique (i.e. it is a UNIQUE
**        or PRIMARY KEY Index), and

**
**     2. The index uses the same collation sequence as the comparison
**        performed by expression pX.
**
**     3. The index is a covering index for <column> (either because it
**        is a PRIMARY KEY or was created with a COVERING clause).
**
**   Restriction (3) could be removed by the calling code in where.c.
**
**   Before returning, *piCov is set to the column number of <column> in
**   the value associated with the selected covering or primary key index.
**
** SET MEMBERSHIP TESTS
**
** If the prNotFound parameter is not 0, then the b-tree will be used 
** for fast set membership tests. In this case an epheremal table must 
** be used unless <column> is an INTEGER PRIMARY KEY or an index can 
** be found with <column> as its left-most column.
**
** When the b-tree is being used for membership tests, the calling function
Changes to src/where.c.
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
** the rowids returned by a WHERE clause.  Return FALSE if doing an
** UPDATE or DELETE might change subsequent WHERE clause results.
*/
int sqlite4WhereOkOnePass(WhereInfo *pWInfo){
  return pWInfo->okOnePass;
}


/*
** Move the content of pSrc into pDest
*/
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
  pDest->n = pSrc->n;
  memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
}







<







530
531
532
533
534
535
536

537
538
539
540
541
542
543
** the rowids returned by a WHERE clause.  Return FALSE if doing an
** UPDATE or DELETE might change subsequent WHERE clause results.
*/
int sqlite4WhereOkOnePass(WhereInfo *pWInfo){
  return pWInfo->okOnePass;
}


/*
** Move the content of pSrc into pDest
*/
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
  pDest->n = pSrc->n;
  memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
}
639
640
641
642
643
644
645





646
647


648
649
650
651
652
653
654
  }
}


/*
** Skip over any TK_COLLATE and/or TK_AS operators at the root of
** an expression.





*/
Expr *sqlite4ExprSkipCollate(Expr *pExpr){


  while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){
    pExpr = pExpr->pLeft;
  }
  return pExpr;
}

/*







>
>
>
>
>

|
>
>







638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  }
}


/*
** Skip over any TK_COLLATE and/or TK_AS operators at the root of
** an expression.
**
** NOTE: This function was added when the NGQP was imported from SQLite3.
** At present it is not actually possible for Expr.op to be set to 
** TK_COLLATE. But will be if the way Expr objects represent collation
** sequences is changed to match SQLite3.
*/
static Expr *sqlite4ExprSkipCollate(Expr *pExpr){
  assert( pExpr==0 || pExpr->op!=TK_COLLATE );

  while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){
    pExpr = pExpr->pLeft;
  }
  return pExpr;
}

/*
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
        }
      }else{
        const char *zCover = (flags & WHERE_IDX_ONLY) ? " COVERING" : "";
        zMsg = sqlite4MAppendf(db, zMsg, "%s USING%s INDEX %s%s",
            zMsg, zCover, pIdx->zName, zWhere
        );
      }

      sqlite4DbFree(db, zWhere);
#if 0
    }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
      zMsg = sqlite4MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);

      if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
        zMsg = sqlite4MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
      }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
        zMsg = sqlite4MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
      }else if( flags&WHERE_BTM_LIMIT ){
        zMsg = sqlite4MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
      }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){
        zMsg = sqlite4MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
      }
#endif
    }
#ifndef SQLITE4_OMIT_VIRTUALTABLE
    else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
      zMsg = sqlite4MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
                  pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    }
#endif







<

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







3272
3273
3274
3275
3276
3277
3278

3279














3280
3281
3282
3283
3284
3285
3286
        }
      }else{
        const char *zCover = (flags & WHERE_IDX_ONLY) ? " COVERING" : "";
        zMsg = sqlite4MAppendf(db, zMsg, "%s USING%s INDEX %s%s",
            zMsg, zCover, pIdx->zName, zWhere
        );
      }

      sqlite4DbFree(db, zWhere);














    }
#ifndef SQLITE4_OMIT_VIRTUALTABLE
    else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
      zMsg = sqlite4MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
                  pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    }
#endif
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
    pLevel->p1 = iCur;
    pLevel->p2 = sqlite4VdbeCurrentAddr(v);
    sqlite4ReleaseTempRange(pParse, iReg, nConstraint+2);
    sqlite4ExprCachePop(pParse, 1);
  }else
#endif /* SQLITE4_OMIT_VIRTUALTABLE */

#if 0
  if( (pLoop->wsFlags & WHERE_IPK)!=0
   && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
  ){
    assert( 0 );

    /* Case 2:  We can directly reference a single row using an
    **          equality comparison against the ROWID field.  Or
    **          we reference multiple rows using a "rowid IN (...)"
    **          construct.
    */
    assert( pLoop->u.btree.nEq==1 );
    iReleaseReg = sqlite4GetTempReg(pParse);
    pTerm = pLoop->aLTerm[0];
    assert( pTerm!=0 );
    assert( pTerm->pExpr!=0 );
    assert( omitTable==0 );
    testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
    iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
    addrNxt = pLevel->addrNxt;
    sqlite4VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
    sqlite4VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
    sqlite4ExprCacheAffinityChange(pParse, iRowidReg, 1);
    sqlite4ExprCacheStore(pParse, iCur, -1, iRowidReg);
    VdbeComment((v, "pk"));
    pLevel->op = OP_Noop;
  }else if( (pLoop->wsFlags & WHERE_IPK)!=0
         && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
  ){
    /* Case 3:  We have an inequality comparison against the ROWID field.
    */
    int testOp = OP_Noop;
    int start;
    int memEndValue = 0;
    WhereTerm *pStart, *pEnd;

    assert( 0 );

    assert( omitTable==0 );
    j = 0;
    pStart = pEnd = 0;
    if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
    if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++];
    assert( pStart!=0 || pEnd!=0 );
    if( bRev ){
      pTerm = pStart;
      pStart = pEnd;
      pEnd = pTerm;
    }
    if( pStart ){
      Expr *pX;             /* The expression that defines the start bound */
      int r1, rTemp;        /* Registers for holding the start boundary */

      /* The following constant maps TK_xx codes into corresponding 
      ** seek opcodes.  It depends on a particular ordering of TK_xx
      */
      const u8 aMoveOp[] = {
           /* TK_GT */  OP_SeekGt,
           /* TK_LE */  OP_SeekLe,
           /* TK_LT */  OP_SeekLt,
           /* TK_GE */  OP_SeekGe
      };
      assert( TK_LE==TK_GT+1 );      /* Make sure the ordering.. */
      assert( TK_LT==TK_GT+2 );      /*  ... of the TK_xx values... */
      assert( TK_GE==TK_GT+3 );      /*  ... is correcct. */

      assert( (pStart->wtFlags & TERM_VNULL)==0 );
      testcase( pStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
      pX = pStart->pExpr;
      assert( pX!=0 );
      testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
      r1 = sqlite4ExprCodeTemp(pParse, pX->pRight, &rTemp);
      sqlite4VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
      VdbeComment((v, "pk"));
      sqlite4ExprCacheAffinityChange(pParse, r1, 1);
      sqlite4ReleaseTempReg(pParse, rTemp);
      disableTerm(pLevel, pStart);
    }else{
      sqlite4VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
    }
    if( pEnd ){
      Expr *pX;
      pX = pEnd->pExpr;
      assert( pX!=0 );
      assert( (pEnd->wtFlags & TERM_VNULL)==0 );
      testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
      testcase( pEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
      memEndValue = ++pParse->nMem;
      sqlite4ExprCode(pParse, pX->pRight, memEndValue);
      if( pX->op==TK_LT || pX->op==TK_GT ){
        testOp = bRev ? OP_Le : OP_Ge;
      }else{
        testOp = bRev ? OP_Lt : OP_Gt;
      }
      disableTerm(pLevel, pEnd);
    }
    start = sqlite4VdbeCurrentAddr(v);
    pLevel->op = bRev ? OP_Prev : OP_Next;
    pLevel->p1 = iCur;
    pLevel->p2 = start;
    assert( pLevel->p5==0 );
    if( testOp!=OP_Noop ){
      iRowidReg = iReleaseReg = sqlite4GetTempReg(pParse);
      sqlite4VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
      sqlite4ExprCacheStore(pParse, iCur, -1, iRowidReg);
      sqlite4VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
      sqlite4VdbeChangeP5(v, SQLITE4_AFF_NUMERIC | SQLITE4_JUMPIFNULL);
    }
  }else 
#endif
  if( pLoop->wsFlags & WHERE_INDEXED ){
    /* Case 4: A scan using an index.
    **
    **         The WHERE clause may contain zero or more equality 
    **         terms ("==" or "IN" operators) that refer to the N
    **         left-most columns of the index. It may also contain
    **         inequality constraints (>, <, >= or <=) on the indexed







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







3405
3406
3407
3408
3409
3410
3411














































































































3412
3413
3414
3415
3416
3417
3418
    pLevel->p1 = iCur;
    pLevel->p2 = sqlite4VdbeCurrentAddr(v);
    sqlite4ReleaseTempRange(pParse, iReg, nConstraint+2);
    sqlite4ExprCachePop(pParse, 1);
  }else
#endif /* SQLITE4_OMIT_VIRTUALTABLE */















































































































  if( pLoop->wsFlags & WHERE_INDEXED ){
    /* Case 4: A scan using an index.
    **
    **         The WHERE clause may contain zero or more equality 
    **         terms ("==" or "IN" operators) that refer to the N
    **         left-most columns of the index. It may also contain
    **         inequality constraints (>, <, >= or <=) on the indexed
3945
3946
3947
3948
3949
3950
3951

3952
3953
3954
3955
3956
3957
3958
        }
        /* Loop through table entries that match term pOrTerm. */
        pSubWInfo = sqlite4WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
                        WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
                        WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
        assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed );
        if( pSubWInfo ){

          explainOneScan(
              pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
          );
          if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
            int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
            sqlite4VdbeAddOp2(v, OP_RowKey, iCur, regKey);
            sqlite4VdbeAddOp4Int(v, OP_RowSetTest, regKeyset,







>







3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
        }
        /* Loop through table entries that match term pOrTerm. */
        pSubWInfo = sqlite4WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
                        WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
                        WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
        assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed );
        if( pSubWInfo ){
          WhereLoop *pSubLoop;
          explainOneScan(
              pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
          );
          if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
            int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
            sqlite4VdbeAddOp2(v, OP_RowKey, iCur, regKey);
            sqlite4VdbeAddOp4Int(v, OP_RowSetTest, regKeyset,
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989



3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000

4001


4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020


4021
4022
4023
4024
4025
4026
4027
          ** If the call to sqlite4WhereBegin() above resulted in a scan that
          ** uses an index, and this is either the first OR-connected term
          ** processed or the index is the same as that used by all previous
          ** terms, set pCov to the candidate covering index. Otherwise, set 
          ** pCov to NULL to indicate that no candidate covering index will 
          ** be available.
          */
#if 0
          pSubLoop = pSubWInfo->a[0].pWLoop;
          assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
          if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
           && (ii==0 || pSubLoop->u.btree.pIndex==pCov)
          ){
            assert( pSubWInfo->a[0].iIdxCur==iCovCur );
            pCov = pSubLoop->u.btree.pIndex;



          }else{
            pCov = 0;
          }
#endif

          /* Finish the loop through table entries that match term pOrTerm. */
          sqlite4WhereEnd(pSubWInfo);
        }
      }
    }
    pLevel->u.pCovidx = pCov;

    if( pCov ) pLevel->iIdxCur = iCovCur;


    if( pAndExpr ){
      pAndExpr->pLeft = 0;
      sqlite4ExprDelete(pParse->db, pAndExpr);
    }
    sqlite4VdbeChangeP1(v, iRetInit, sqlite4VdbeCurrentAddr(v));
    sqlite4VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
    sqlite4VdbeResolveLabel(v, iLoopBody);

    if( pWInfo->nLevel>1 ) sqlite4StackFree(pParse->db, pOrTab);
    if( !untestedTerms ) disableTerm(pLevel, pTerm);
  }else
#endif /* SQLITE4_OMIT_OR_OPTIMIZATION */

  {
    /* TODO: This case is currently being used. Why can't it use the 
    ** index case instead? */ 

    /* Case 6:  There is no usable index.  We must do a complete
    **          scan of the entire table.


    */
    static const u8 aStep[] = { OP_Next, OP_Prev };
    static const u8 aStart[] = { OP_Rewind, OP_Last };
    assert( bRev==0 || bRev==1 );
    pLevel->op = aStep[bRev];
    pLevel->p1 = iCur;
    pLevel->p2 = 1 + sqlite4VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);







<





<

>
>
>



<






|
>
|
>
>














<
<
<

|
>
>







3857
3858
3859
3860
3861
3862
3863

3864
3865
3866
3867
3868

3869
3870
3871
3872
3873
3874
3875

3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900



3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
          ** If the call to sqlite4WhereBegin() above resulted in a scan that
          ** uses an index, and this is either the first OR-connected term
          ** processed or the index is the same as that used by all previous
          ** terms, set pCov to the candidate covering index. Otherwise, set 
          ** pCov to NULL to indicate that no candidate covering index will 
          ** be available.
          */

          pSubLoop = pSubWInfo->a[0].pWLoop;
          assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
          if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
           && (ii==0 || pSubLoop->u.btree.pIndex==pCov)
          ){

            pCov = pSubLoop->u.btree.pIndex;
            assert( pCov->eIndexType==SQLITE4_INDEX_PRIMARYKEY 
                 || pSubWInfo->a[0].iIdxCur==iCovCur 
            );
          }else{
            pCov = 0;
          }


          /* Finish the loop through table entries that match term pOrTerm. */
          sqlite4WhereEnd(pSubWInfo);
        }
      }
    }
    assert( pLevel->u.pCovidx==0 );
    if( pCov && pCov->eIndexType!=SQLITE4_INDEX_PRIMARYKEY ){
      pLevel->iIdxCur = iCovCur;
      pLevel->u.pCovidx = pCov;
    }
    if( pAndExpr ){
      pAndExpr->pLeft = 0;
      sqlite4ExprDelete(pParse->db, pAndExpr);
    }
    sqlite4VdbeChangeP1(v, iRetInit, sqlite4VdbeCurrentAddr(v));
    sqlite4VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
    sqlite4VdbeResolveLabel(v, iLoopBody);

    if( pWInfo->nLevel>1 ) sqlite4StackFree(pParse->db, pOrTab);
    if( !untestedTerms ) disableTerm(pLevel, pTerm);
  }else
#endif /* SQLITE4_OMIT_OR_OPTIMIZATION */

  {



    /* Case 6:  There is no usable index.  We must do a complete
    **          scan of the entire table. This comes up when scanning
    **          through b-trees containing materialized sub-queries or 
    **          views.
    */
    static const u8 aStep[] = { OP_Next, OP_Prev };
    static const u8 aStart[] = { OP_Rewind, OP_Last };
    assert( bRev==0 || bRev==1 );
    pLevel->op = aStep[bRev];
    pLevel->p1 = iCur;
    pLevel->p2 = 1 + sqlite4VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
     && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 
    ){
      WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
      WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
      WhereTerm *pOrTerm;
      int once = 1;
      int i, j;

      pItem = pWInfo->pTabList->a + pNew->iTab;
      iCur = pItem->iCursor;
      sSubBuild = *pBuilder;
      sSubBuild.pOrderBy = 0;
      sSubBuild.pOrSet = &sCur;

      for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
        if( (pOrTerm->eOperator & WO_AND)!=0 ){
          sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
        }else if( pOrTerm->leftCursor==iCur ){
          tempWC.pWInfo = pWC->pWInfo;
          tempWC.pOuter = pWC;
          tempWC.op = TK_AND;
          tempWC.nTerm = 1;
          tempWC.a = pOrTerm;
          sSubBuild.pWC = &tempWC;
        }else{
          continue;
        }

        sCur.n = 0;
#ifndef SQLITE4_OMIT_VIRTUALTABLE
        if( IsVirtual(pItem->pTab) ){
          rc = whereLoopAddVirtual(&sSubBuild);
          for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra;
        }else
#endif
        {
          rc = whereLoopAddBtree(&sSubBuild, mExtra);
        }

        assert( rc==SQLITE4_OK || sCur.n==0 );
        if( sCur.n==0 ){
          sSum.n = 0;
          break;
        }else if( once ){
          whereOrMove(&sSum, &sCur);
          once = 0;
        }else{
          whereOrMove(&sPrev, &sSum);
          sSum.n = 0;
          for(i=0; i<sPrev.n; i++){
            for(j=0; j<sCur.n; j++){
              whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
                  whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
                  whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
            }
          }
        }
      }
      pNew->nLTerm = 1;
      pNew->aLTerm[0] = pTerm;
      pNew->wsFlags = WHERE_MULTI_OR;







|



















<










<













|
|







4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891

4892
4893
4894
4895
4896
4897
4898
4899
4900
4901

4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
     && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 
    ){
      WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
      WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
      WhereTerm *pOrTerm;
      int once = 1;
      int i, j;
    
      pItem = pWInfo->pTabList->a + pNew->iTab;
      iCur = pItem->iCursor;
      sSubBuild = *pBuilder;
      sSubBuild.pOrderBy = 0;
      sSubBuild.pOrSet = &sCur;

      for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
        if( (pOrTerm->eOperator & WO_AND)!=0 ){
          sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
        }else if( pOrTerm->leftCursor==iCur ){
          tempWC.pWInfo = pWC->pWInfo;
          tempWC.pOuter = pWC;
          tempWC.op = TK_AND;
          tempWC.nTerm = 1;
          tempWC.a = pOrTerm;
          sSubBuild.pWC = &tempWC;
        }else{
          continue;
        }

        sCur.n = 0;
#ifndef SQLITE4_OMIT_VIRTUALTABLE
        if( IsVirtual(pItem->pTab) ){
          rc = whereLoopAddVirtual(&sSubBuild);
          for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra;
        }else
#endif
        {
          rc = whereLoopAddBtree(&sSubBuild, mExtra);
        }

        assert( rc==SQLITE4_OK || sCur.n==0 );
        if( sCur.n==0 ){
          sSum.n = 0;
          break;
        }else if( once ){
          whereOrMove(&sSum, &sCur);
          once = 0;
        }else{
          whereOrMove(&sPrev, &sSum);
          sSum.n = 0;
          for(i=0; i<sPrev.n; i++){
            for(j=0; j<sCur.n; j++){
              whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
                            whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
                            whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
            }
          }
        }
      }
      pNew->nLTerm = 1;
      pNew->aLTerm[0] = pTerm;
      pNew->wsFlags = WHERE_MULTI_OR;
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
        pNew->prereq = sSum.a[i].prereq;
        rc = whereLoopInsert(pBuilder, pNew);
      }
    }
  }
  return rc;
}


/*
** Add all WhereLoop objects for all tables 
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
  WhereInfo *pWInfo = pBuilder->pWInfo;
  Bitmask mExtra = 0;







<







4931
4932
4933
4934
4935
4936
4937

4938
4939
4940
4941
4942
4943
4944
        pNew->prereq = sSum.a[i].prereq;
        rc = whereLoopInsert(pBuilder, pNew);
      }
    }
  }
  return rc;
}


/*
** Add all WhereLoop objects for all tables 
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
  WhereInfo *pWInfo = pBuilder->pWInfo;
  Bitmask mExtra = 0;
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
        if( sqlite4_stricmp(z1, z2)!=0 ) continue;
      }
      obSat |= MASKBIT(i);
    }

    if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){
      Index *pPk = 0;
#if 0
      if( pLoop->wsFlags & WHERE_IPK ){
        pIndex = 0;
        nColumn = 0;
      }else 
#endif
      if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
        return 0;
      }else{
        isOrderDistinct = pIndex->onError!=OE_None;
        pPk = sqlite4FindPrimaryKey(pIndex->pTable, 0);
        nColumn = idxColumnCount(pIndex, pPk);
      }







<
<
<
<
<
<







5098
5099
5100
5101
5102
5103
5104






5105
5106
5107
5108
5109
5110
5111
        if( sqlite4_stricmp(z1, z2)!=0 ) continue;
      }
      obSat |= MASKBIT(i);
    }

    if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){
      Index *pPk = 0;






      if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
        return 0;
      }else{
        isOrderDistinct = pIndex->onError!=OE_None;
        pPk = sqlite4FindPrimaryKey(pIndex->pTable, 0);
        nColumn = idxColumnCount(pIndex, pPk);
      }
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
#endif
    if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
         && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
      int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
      sqlite4OpenPrimaryKey(pParse, pTabItem->iCursor, iDb, pTab, op);
      testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
      testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
#if 0
      if( !pWInfo->okOnePass && pTab->nCol<BMS ){
        Bitmask b = pTabItem->colUsed;
        int n = 0;
        for(; b; b=b>>1, n++){}
        sqlite4VdbeChangeP4(v, sqlite4VdbeCurrentAddr(v)-1, 
                            SQLITE4_INT_TO_PTR(n), P4_INT32);
        assert( n<=pTab->nCol );
      }
#endif
    }
#if 0
    else{
      sqlite4TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
    }
#endif
#ifndef SQLITE4_OMIT_AUTOMATIC_INDEX
    if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
      constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel);
    }else
#endif
    if( pLoop->wsFlags & WHERE_INDEXED ){
      Index *pIx = pLoop->u.btree.pIndex;







<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<







5966
5967
5968
5969
5970
5971
5972








5973







5974
5975
5976
5977
5978
5979
5980
#endif
    if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
         && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
      int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
      sqlite4OpenPrimaryKey(pParse, pTabItem->iCursor, iDb, pTab, op);
      testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
      testcase( !pWInfo->okOnePass && pTab->nCol==BMS );








    }







#ifndef SQLITE4_OMIT_AUTOMATIC_INDEX
    if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
      constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel);
    }else
#endif
    if( pLoop->wsFlags & WHERE_INDEXED ){
      Index *pIx = pLoop->u.btree.pIndex;