/ Check-in [adcef73b]
Login

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

Overview
Comment:Comment and variable-name cleanup in where.c. Add testcase() macros to insure adequate test coverage of table-driven logic. (CVS 5032)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: adcef73b3925266a14a552cd9b06c14f22aaefc8
User & Date: drh 2008-04-19 14:40:44
Context
2008-04-19
20:34
Continuing work on journal_mode. Journal_mode=persist now appears to be working, though additional testing would be welcomed. (CVS 5033) check-in: 277e4099 user: drh tags: trunk
14:40
Comment and variable-name cleanup in where.c. Add testcase() macros to insure adequate test coverage of table-driven logic. (CVS 5032) check-in: adcef73b user: drh tags: trunk
14:06
Fix a typo in the documentation on sqlite3_open_v2(). (CVS 5031) check-in: f7b62daa user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/where.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
....
1268
1269
1270
1271
1272
1273
1274

1275
1276

1277
1278
1279
1280
1281
1282
1283
....
1316
1317
1318
1319
1320
1321
1322

1323
1324

1325
1326
1327
1328
1329
1330
1331
....
1863
1864
1865
1866
1867
1868
1869


1870
1871
1872
1873
1874
1875
1876
....
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
....
2468
2469
2470
2471
2472
2473
2474

2475
2476
2477




2478
2479
2480
2481
2482
2483
2484
....
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
....
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
....
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
....
2631
2632
2633
2634
2635
2636
2637


2638
2639
2640
2641
2642
2643
2644
....
2652
2653
2654
2655
2656
2657
2658


2659
2660
2661
2662
2663
2664
2665
....
2686
2687
2688
2689
2690
2691
2692


2693
2694
2695
2696
2697
2698
2699
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  This module is reponsible for
** generating the code that loops through a table looking for applicable
** rows.  Indices are selected and used to speed the search when doing
** so is applicable.  Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.301 2008/04/18 10:25:24 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
*/
#define BMS  (sizeof(Bitmask)*8)
................................................................................
    int nTerm;
    WHERETRACE(("Recomputing index info for %s...\n", pTab->zName));

    /* Count the number of possible WHERE clause constraints referring
    ** to this virtual table */
    for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
      if( pTerm->leftCursor != pSrc->iCursor ) continue;

      if( pTerm->eOperator==WO_IN ) continue;
      if( pTerm->eOperator==WO_ISNULL ) continue;

      nTerm++;
    }

    /* If the ORDER BY clause contains only columns in the current 
    ** virtual table then allocate space for the aOrderBy part of
    ** the sqlite3_index_info structure.
    */
................................................................................
    *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
    *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
    *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
                                                                     pUsage;

    for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
      if( pTerm->leftCursor != pSrc->iCursor ) continue;

      if( pTerm->eOperator==WO_IN ) continue;
      if( pTerm->eOperator==WO_ISNULL ) continue;

      pIdxCons[j].iColumn = pTerm->leftColumn;
      pIdxCons[j].iTermOffset = i;
      pIdxCons[j].op = pTerm->eOperator;
      /* The direct assignment in the previous line is possible only because
      ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
      ** following asserts verify this fact. */
      assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
................................................................................
    pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
    if( pTerm==0 ) break;
    assert( (pTerm->flags & TERM_CODED)==0 );
    r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
    if( r1!=regBase+j ){
      sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
    }


    if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
      sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
    }
  }
  return regBase;
}

................................................................................
        sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1);
        sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
        sqlite3ReleaseTempReg(pParse, r1);
      }
    }else if( pLevel->flags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
      /* Case 3: A scan using an index.
      **
      **         The WHERE clause may contain one 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
      **         column that immediately follows the N equalities. Only 
      **         the right-most column can be an inequality - the rest must
      **         use the "==" and "IN" operators. For example, if the 
      **         index is on (x,y,z), then the following clauses are all 
................................................................................
      **
      **            x=5
      **            x=5 AND y=10
      **            x=5 AND y<10
      **            x=5 AND y>5 AND y<10
      **            x=5 AND y=5 AND z<=10
      **

      **         This cannot be optimized:
      **
      **            x=5 AND z<10




      **
      **         This case is also used when there are no WHERE clause
      **         constraints but an index is selected anyway, in order
      **         to force the output order to conform to an ORDER BY.
      */  
      int aStartOp[] = {
        0,
................................................................................
      int r1;                      /* Temp register */
      WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
      WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
      int startEq;                 /* True if range start uses ==, >= or <= */
      int endEq;                   /* True if range end uses ==, >= or <= */
      int start_constraints;       /* Start of range is constrained */
      int k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
      char *ptr;
      int op;

      /* Generate code to evaluate all constraint terms using == or IN
      ** and store the values of those terms in an array of registers
      ** starting at regBase.
      */
      regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2);
................................................................................
        pRangeStart = findTerm(&wc, iCur, k, notReady, (WO_GT|WO_GE), pIdx);
      }

      /* If we are doing a reverse order scan on an ascending index, or
      ** a forward order scan on a descending index, interchange the 
      ** start and end terms (pRangeStart and pRangeEnd).
      */
      if( bRev==((pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)?1:0) ){
        SWAP(WhereTerm *, pRangeEnd, pRangeStart);
      }





      startEq = ((!pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE))?1:0);
      endEq = ((!pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE))?1:0);
      start_constraints = ((pRangeStart || nEq>0)?1:0);

      /* Seek the index cursor to the start of the range. */
      ptr = (char *)(sqlite3_intptr_t)nEq;

      if( pRangeStart ){
        int dcc = pParse->disableColCache;
        if( pRangeEnd ){
          pParse->disableColCache = 1;
        }
        sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
        pParse->disableColCache = dcc;
        sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
        ptr++;
      }else if( isMinQuery ){
        sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
        ptr++;
        startEq = 0;
        start_constraints = 1;
      }
      codeApplyAffinity(pParse, regBase, (int)ptr, pIdx);
      op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];







      sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, ptr, P4_INT32);


      /* Load the value for the inequality constraint at the end of the
      ** range (if any).
      */
      ptr = (char *)(sqlite3_intptr_t)nEq;
      if( pRangeEnd ){
        sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
        sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
        codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
        ptr++;
      }

      /* Top of the loop body */
      pLevel->p2 = sqlite3VdbeCurrentAddr(v);

      /* Check if the index cursor is past the end of the range. */
      op = aEndOp[((pRangeEnd || nEq)?1:0) * (1 + bRev)];



      sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, ptr, P4_INT32);

      sqlite3VdbeChangeP5(v, endEq!=bRev);

      /* If there are inequality constraints (there may not be if the
      ** index is only being used to optimize ORDER BY), check that the
      ** value of the table column the inequality contrains is not NULL.
      ** If it is, jump to the next iteration of the loop.
      */
      r1 = sqlite3GetTempReg(pParse);


      if( pLevel->flags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
        sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
        sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
      }

      /* Seek the table cursor, if required */
      if( !omitTable ){
................................................................................
      ** WHERE clause terms made redundant by the index range scan.
      */
      pLevel->op = bRev ? OP_Prev : OP_Next;
      pLevel->p1 = iIdxCur;
      disableTerm(pLevel, pRangeStart);
      disableTerm(pLevel, pRangeEnd);
    }else{
      /* Case 5:  There is no usable index.  We must do a complete
      **          scan of the entire table.
      */
      assert( omitTable==0 );
      assert( bRev==0 );
      pLevel->op = OP_Next;
      pLevel->p1 = iCur;
      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, brk);
................................................................................
    notReady &= ~getMask(&maskSet, iCur);

    /* Insert code to test every subexpression that can be completely
    ** computed using the current set of tables.
    */
    for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){
      Expr *pE;


      if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
      if( (pTerm->prereqAll & notReady)!=0 ) continue;
      pE = pTerm->pExpr;
      assert( pE!=0 );
      if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
        continue;
      }
................................................................................
    if( pLevel->iLeftJoin ){
      pLevel->top = sqlite3VdbeCurrentAddr(v);
      sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
      VdbeComment((v, "record LEFT JOIN hit"));
      sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur);
      sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur);
      for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){


        if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
        if( (pTerm->prereqAll & notReady)!=0 ) continue;
        assert( pTerm->pExpr );
        sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, SQLITE_JUMPIFNULL);
        pTerm->flags |= TERM_CODED;
      }
    }
................................................................................
        nQPlan += 2;
      }else{
        memcpy(&sqlite3_query_plan[nQPlan], z, n);
        nQPlan += n;
      }
      sqlite3_query_plan[nQPlan++] = ' ';
    }


    if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
      memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
      nQPlan += 2;
    }else if( pLevel->pIdx==0 ){
      memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3);
      nQPlan += 3;
    }else{







|







 







>
|
|
>







 







>
|
|
>







 







>
>







 







|







 







>
|


>
>
>
>







 







|







 







|



>
>
>
>
|
|
|


<
>








|


|



|

>
>
>
>
>
>
>
|
>




|




|






|
>
>
>
|
>


|
<
|



>
>







 







|







 







>
>







 







>
>







 







>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
....
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
....
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
....
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
....
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
....
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
....
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
....
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
2620
2621
2622
2623

2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
....
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
....
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
....
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
....
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  This module is reponsible for
** generating the code that loops through a table looking for applicable
** rows.  Indices are selected and used to speed the search when doing
** so is applicable.  Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.302 2008/04/19 14:40:44 drh Exp $
*/
#include "sqliteInt.h"

/*
** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
*/
#define BMS  (sizeof(Bitmask)*8)
................................................................................
    int nTerm;
    WHERETRACE(("Recomputing index info for %s...\n", pTab->zName));

    /* Count the number of possible WHERE clause constraints referring
    ** to this virtual table */
    for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
      if( pTerm->leftCursor != pSrc->iCursor ) continue;
      if( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
      testcase( pTerm->eOperator==WO_IN );
      testcase( pTerm->eOperator==WO_ISNULL );
      if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
      nTerm++;
    }

    /* If the ORDER BY clause contains only columns in the current 
    ** virtual table then allocate space for the aOrderBy part of
    ** the sqlite3_index_info structure.
    */
................................................................................
    *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
    *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
    *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
                                                                     pUsage;

    for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
      if( pTerm->leftCursor != pSrc->iCursor ) continue;
      if( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
      testcase( pTerm->eOperator==WO_IN );
      testcase( pTerm->eOperator==WO_ISNULL );
      if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue;
      pIdxCons[j].iColumn = pTerm->leftColumn;
      pIdxCons[j].iTermOffset = i;
      pIdxCons[j].op = pTerm->eOperator;
      /* The direct assignment in the previous line is possible only because
      ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical.  The
      ** following asserts verify this fact. */
      assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
................................................................................
    pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
    if( pTerm==0 ) break;
    assert( (pTerm->flags & TERM_CODED)==0 );
    r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
    if( r1!=regBase+j ){
      sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
    }
    testcase( pTerm->eOperator & WO_ISNULL );
    testcase( pTerm->eOperator & WO_IN );
    if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
      sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
    }
  }
  return regBase;
}

................................................................................
        sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1);
        sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
        sqlite3ReleaseTempReg(pParse, r1);
      }
    }else if( pLevel->flags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){
      /* Case 3: 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
      **         column that immediately follows the N equalities. Only 
      **         the right-most column can be an inequality - the rest must
      **         use the "==" and "IN" operators. For example, if the 
      **         index is on (x,y,z), then the following clauses are all 
................................................................................
      **
      **            x=5
      **            x=5 AND y=10
      **            x=5 AND y<10
      **            x=5 AND y>5 AND y<10
      **            x=5 AND y=5 AND z<=10
      **
      **         The z<10 term of the following cannot be used, only
      **         the x=5 term:
      **
      **            x=5 AND z<10
      **
      **         N may be zero if there are inequality constraints.
      **         If there are no inequality constraints, then N is at
      **         least one.
      **
      **         This case is also used when there are no WHERE clause
      **         constraints but an index is selected anyway, in order
      **         to force the output order to conform to an ORDER BY.
      */  
      int aStartOp[] = {
        0,
................................................................................
      int r1;                      /* Temp register */
      WhereTerm *pRangeStart = 0;  /* Inequality constraint at range start */
      WhereTerm *pRangeEnd = 0;    /* Inequality constraint at range end */
      int startEq;                 /* True if range start uses ==, >= or <= */
      int endEq;                   /* True if range end uses ==, >= or <= */
      int start_constraints;       /* Start of range is constrained */
      int k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
      int nConstraint;             /* Number of constraint terms */
      int op;

      /* Generate code to evaluate all constraint terms using == or IN
      ** and store the values of those terms in an array of registers
      ** starting at regBase.
      */
      regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2);
................................................................................
        pRangeStart = findTerm(&wc, iCur, k, notReady, (WO_GT|WO_GE), pIdx);
      }

      /* If we are doing a reverse order scan on an ascending index, or
      ** a forward order scan on a descending index, interchange the 
      ** start and end terms (pRangeStart and pRangeEnd).
      */
      if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
        SWAP(WhereTerm *, pRangeEnd, pRangeStart);
      }

      testcase( pRangeStart && pRangeStart->eOperator & WO_LE );
      testcase( pRangeStart && pRangeStart->eOperator & WO_GE );
      testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE );
      testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE );
      startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
      endEq =   !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
      start_constraints = pRangeStart || nEq>0;

      /* Seek the index cursor to the start of the range. */

      nConstraint = nEq;
      if( pRangeStart ){
        int dcc = pParse->disableColCache;
        if( pRangeEnd ){
          pParse->disableColCache = 1;
        }
        sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
        pParse->disableColCache = dcc;
        sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
        nConstraint++;
      }else if( isMinQuery ){
        sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
        nConstraint++;
        startEq = 0;
        start_constraints = 1;
      }
      codeApplyAffinity(pParse, regBase, nConstraint, pIdx);
      op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
      assert( op!=0 );
      testcase( op==OP_Rewind );
      testcase( op==OP_Last );
      testcase( op==OP_MoveGt );
      testcase( op==OP_MoveGe );
      testcase( op==OP_MoveLe );
      testcase( op==OP_MoveLt );
      sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, 
                        (char*)nConstraint, P4_INT32);

      /* Load the value for the inequality constraint at the end of the
      ** range (if any).
      */
      nConstraint = nEq;
      if( pRangeEnd ){
        sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
        sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
        codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
        nConstraint++;
      }

      /* Top of the loop body */
      pLevel->p2 = sqlite3VdbeCurrentAddr(v);

      /* Check if the index cursor is past the end of the range. */
      op = aEndOp[(pRangeEnd || nEq) * (1 + bRev)];
      testcase( op==OP_Noop );
      testcase( op==OP_IdxGE );
      testcase( op==OP_IdxLT );
      sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase,
                        (char*)nConstraint, P4_INT32);
      sqlite3VdbeChangeP5(v, endEq!=bRev);

      /* If there are inequality constraints, check that the value

      ** of the table column that the inequality contrains is not NULL.
      ** If it is, jump to the next iteration of the loop.
      */
      r1 = sqlite3GetTempReg(pParse);
      testcase( pLevel->flags & WHERE_BTM_LIMIT );
      testcase( pLevel->flags & WHERE_TOP_LIMIT );
      if( pLevel->flags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
        sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
        sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
      }

      /* Seek the table cursor, if required */
      if( !omitTable ){
................................................................................
      ** WHERE clause terms made redundant by the index range scan.
      */
      pLevel->op = bRev ? OP_Prev : OP_Next;
      pLevel->p1 = iIdxCur;
      disableTerm(pLevel, pRangeStart);
      disableTerm(pLevel, pRangeEnd);
    }else{
      /* Case 4:  There is no usable index.  We must do a complete
      **          scan of the entire table.
      */
      assert( omitTable==0 );
      assert( bRev==0 );
      pLevel->op = OP_Next;
      pLevel->p1 = iCur;
      pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, brk);
................................................................................
    notReady &= ~getMask(&maskSet, iCur);

    /* Insert code to test every subexpression that can be completely
    ** computed using the current set of tables.
    */
    for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){
      Expr *pE;
      testcase( pTerm->flags & TERM_VIRTUAL );
      testcase( pTerm->flags & TERM_CODED );
      if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
      if( (pTerm->prereqAll & notReady)!=0 ) continue;
      pE = pTerm->pExpr;
      assert( pE!=0 );
      if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
        continue;
      }
................................................................................
    if( pLevel->iLeftJoin ){
      pLevel->top = sqlite3VdbeCurrentAddr(v);
      sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
      VdbeComment((v, "record LEFT JOIN hit"));
      sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur);
      sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur);
      for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
        testcase( pTerm->flags & TERM_VIRTUAL );
        testcase( pTerm->flags & TERM_CODED );
        if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
        if( (pTerm->prereqAll & notReady)!=0 ) continue;
        assert( pTerm->pExpr );
        sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, SQLITE_JUMPIFNULL);
        pTerm->flags |= TERM_CODED;
      }
    }
................................................................................
        nQPlan += 2;
      }else{
        memcpy(&sqlite3_query_plan[nQPlan], z, n);
        nQPlan += n;
      }
      sqlite3_query_plan[nQPlan++] = ' ';
    }
    testcase( pLevel->flags & WHERE_ROWID_EQ );
    testcase( pLevel->flags & WHERE_ROWID_RANGE );
    if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
      memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
      nQPlan += 2;
    }else if( pLevel->pIdx==0 ){
      memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3);
      nQPlan += 3;
    }else{