SQLite

Check-in [9a97681924]
Login

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

Overview
Comment:Combine cases 3 and 4 in where.c, since case 4 is now a special case of case 3. (CVS 5029)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9a976819246eb558ba43429f8889972c4a4bce9d
User & Date: danielk1977 2008-04-18 10:25:24.000
Context
2008-04-18
11:31
Remove unused code from OP_IdxLt and OP_IdxGE. (CVS 5030) (check-in: df02175ec0 user: danielk1977 tags: trunk)
10:25
Combine cases 3 and 4 in where.c, since case 4 is now a special case of case 3. (CVS 5029) (check-in: 9a97681924 user: danielk1977 tags: trunk)
09:01
Allow OP_MoveGt and similar to use an array of registers instead of a serialized record. Modify one type of index range scan to use this. (CVS 5028) (check-in: c448f15aa5 user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.731 2008/04/18 09:01:16 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.732 2008/04/18 10:25:24 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
2144
2145
2146
2147
2148
2149
2150

2151
2152
2153
2154
2155
2156
2157
case OP_Affinity: {
  char *zAffinity = pOp->p4.z;
  Mem *pData0 = &p->aMem[pOp->p1];
  Mem *pLast = &pData0[pOp->p2-1];
  Mem *pRec;

  for(pRec=pData0; pRec<=pLast; pRec++){

    applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
  }
  break;
}

/* Opcode: MakeRecord P1 P2 P3 P4 *
**







>







2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
case OP_Affinity: {
  char *zAffinity = pOp->p4.z;
  Mem *pData0 = &p->aMem[pOp->p1];
  Mem *pLast = &pData0[pOp->p2-1];
  Mem *pRec;

  for(pRec=pData0; pRec<=pLast; pRec++){
    ExpandBlob(pRec);
    applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
  }
  break;
}

/* Opcode: MakeRecord P1 P2 P3 P4 *
**
2786
2787
2788
2789
2790
2791
2792
2793
2794

2795



2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811

2812



2813
2814
2815
2816
2817
2818
2819
2820
2821

2822



2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
  int i = pOp->p1;
  assert( i>=0 && i<p->nCursor );
  sqlite3VdbeFreeCursor(p, p->apCsr[i]);
  p->apCsr[i] = 0;
  break;
}

/* Opcode: MoveGe P1 P2 P3 * *
**

** Use the value in register P3 as a key.  Reposition



** cursor P1 so that it points to the smallest entry that is greater
** than or equal to the key in register P3.
** If there are no records greater than or equal to the key and P2 
** is not zero, then jump to P2.
**
** A special feature of this opcode (and different from the
** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is
** zero and P1 is an SQL table (a b-tree with integer keys) then
** the seek is deferred until it is actually needed.  It might be
** the case that the cursor is never accessed.  By deferring the
** seek, we avoid unnecessary seeks.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe
*/
/* Opcode: MoveGt P1 P2 P3 * *
**

** Use the value in register P3 as a key.  Reposition



** cursor P1 so that it points to the smallest entry that is greater
** than the key in register P3.
** If there are no records greater than the key 
** then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe
*/
/* Opcode: MoveLt P1 P2 P3 * * 
**

** Use the value in register P3 as a key.  Reposition



** cursor P1 so that it points to the largest entry that is less
** than the key in register P3.
** If there are no records less than the key
** then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe
*/
/* Opcode: MoveLe P1 P2 P3 P4 *
**
** P4 is always an integer value. If it is zero, then use the value in
** register P3 as a key. Reposition cursor P1 so that it points to the
** largest entry that is less than or equal to the key. If there are no 
** records less than or eqal to the key then jump to P2.
**
** If the integer value in operand P4 is non-zero, then P3 is the first
** of a contiguous array of P4 memory cells that form an unpacked index
** key. In this case the unpacked key is used instead of the value of
** register P3 in the procedure described above.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/
case OP_MoveLt:         /* jump, in3 */
case OP_MoveLe:         /* jump, in3 */
case OP_MoveGe:         /* jump, in3 */
case OP_MoveGt: {       /* jump, in3 */







|

>
|
>
>
>
|
<
|
|










|

>
|
>
>
>
|
<
|
|



|

>
|
>
>
>
|
<
|
|





|
|
|
|

|
|
|
<







2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801

2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821

2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834

2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849

2850
2851
2852
2853
2854
2855
2856
  int i = pOp->p1;
  assert( i>=0 && i<p->nCursor );
  sqlite3VdbeFreeCursor(p, p->apCsr[i]);
  p->apCsr[i] = 0;
  break;
}

/* Opcode: MoveGe P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the integer value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 

** is greater than or equal to the key value. If there are no records 
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** A special feature of this opcode (and different from the
** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is
** zero and P1 is an SQL table (a b-tree with integer keys) then
** the seek is deferred until it is actually needed.  It might be
** the case that the cursor is never accessed.  By deferring the
** seek, we avoid unnecessary seeks.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe
*/
/* Opcode: MoveGt P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the integer value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 

** is greater than the key value. If there are no records greater than 
** the key and P2 is not zero, then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe
*/
/* Opcode: MoveLt P1 P2 P3 P4 * 
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the integer value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the largest entry that 

** is less than the key value. If there are no records less than 
** the key and P2 is not zero, then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe
*/
/* Opcode: MoveLe P1 P2 P3 P4 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the integer value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that it points to the largest entry that 
** is less than or equal to the key value. If there are no records 
** less than or equal to the key and P2 is not zero, then jump to P2.

**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/
case OP_MoveLt:         /* jump, in3 */
case OP_MoveLe:         /* jump, in3 */
case OP_MoveGe:         /* jump, in3 */
case OP_MoveGt: {       /* jump, in3 */
2868
2869
2870
2871
2872
2873
2874

2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
      rc = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)iKey, 0, &res);
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->lastRowid = iKey;
      pC->rowidIsValid = res==0;
    }else{

      int nField = ((pOp->p4type==P4_INT32)?pOp->p4.i:0);
      assert( pIn3->flags&MEM_Blob || nField>0 );
      if( nField==0 ){
        ExpandBlob(pIn3);
        rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
      }else{
        UnpackedRecord r;
        r.pKeyInfo = pC->pKeyInfo;
        r.nField = nField;
        r.needFree = 0;
        r.needDestroy = 0;
        r.aMem = &p->aMem[pOp->p3];
        rc = sqlite3BtreeMoveto(pC->pCursor, 0, &r, 0, 0, &res);
      }
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->rowidIsValid = 0;
    }
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;







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







2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887




2888
2889
2890
2891
2892
2893

2894
2895
2896
2897
2898
2899
2900
      rc = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)iKey, 0, &res);
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->lastRowid = iKey;
      pC->rowidIsValid = res==0;
    }else{
      UnpackedRecord r;
      int nField = pOp->p4.i;
      assert( pOp->p4type==P4_INT32 );
      assert( nField>0 );




      r.pKeyInfo = pC->pKeyInfo;
      r.nField = nField;
      r.needFree = 0;
      r.needDestroy = 0;
      r.aMem = &p->aMem[pOp->p3];
      rc = sqlite3BtreeMoveto(pC->pCursor, 0, &r, 0, 0, &res);

      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->rowidIsValid = 0;
    }
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
Changes to src/where.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** 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.300 2008/04/18 09:01:16 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
*/
#define BMS  (sizeof(Bitmask)*8)







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** 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)
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750

1751
1752
1753
1754
1755
1756
1757
        disableTerm(pLevel, pOther);
      }
    }
  }
}

/*
** Generate code that builds a probe for an index.
**
** There should be nColumn values on the stack.  The index
** to be probed is pIdx.  Pop the values from the stack and
** replace them all with a single record that is the index
** problem.
*/
static void buildIndexProbe(
  Parse *pParse,  /* Parsing and code generation context */
  int nColumn,    /* The number of columns to check for NULL */
  Index *pIdx,    /* Index that we will be searching */
  int regSrc,     /* Take values from this register */
  int regDest     /* Write the result into this register */
){
  Vdbe *v = pParse->pVdbe;
  assert( regSrc>0 );
  assert( regDest>0 );
  assert( v!=0 );
  sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest);
  sqlite3IndexAffinityStr(v, pIdx);
  sqlite3ExprCacheAffinityChange(pParse, regSrc, nColumn);

}


/*
** Generate code for a single equality term of the WHERE clause.  An equality
** term can be either X=expr or X IN (...).   pTerm is the term to be 
** coded.







|
<
<
|
<
<

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







1723
1724
1725
1726
1727
1728
1729
1730


1731


1732
1733





1734
1735


1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
        disableTerm(pLevel, pOther);
      }
    }
  }
}

/*
** Apply the affinities associated with the first n columns of index


** pIdx to the values in the n registers starting at base.


*/
static void codeApplyAffinity(Parse *pParse, int base, int n, Index *pIdx){





  if( n>0 ){
    Vdbe *v = pParse->pVdbe;


    assert( v!=0 );
    sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
    sqlite3IndexAffinityStr(v, pIdx);
    sqlite3ExprCacheAffinityChange(pParse, base, n);
  }
}


/*
** Generate code for a single equality term of the WHERE clause.  An equality
** term can be either X=expr or X IN (...).   pTerm is the term to be 
** coded.
2459
2460
2461
2462
2463
2464
2465
2466


2467
2468
2469
2470

2471
2472












2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
        int r1 = sqlite3GetTempReg(pParse);
        sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
        /* sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); */
        sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1);
        sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
        sqlite3ReleaseTempReg(pParse, r1);
      }
    }else if( pLevel->flags & WHERE_COLUMN_RANGE ){


      /* Case 3: The WHERE clause term that refers to the right-most
      **         column of the index is an inequality.  For example, if
      **         the index is on (x,y,z) and the WHERE clause is of the
      **         form "x=5 AND y<10" then this case is used.  Only the

      **         right-most column can be an inequality - the rest must
      **         use the "==" and "IN" operators.












      **
      **         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,
        0,
        OP_Rewind,           /* 2: (!start_constraints && startEq && !bRev) */
        OP_Last,             /* 3: (!start_constraints && startEq && bRev)  */
        OP_MoveGt,           /* 4: (start_constraints  && !startEq && !bRev) */
        OP_MoveLt,           /* 5: (start_constraints  && !startEq && bRev) */
        OP_MoveGe,           /* 6: (start_constraints  &&  startEq && !bRev) */
        OP_MoveLe            /* 7: (start_constraints  &&  startEq && bRev) */
      };
      int aEndOp[] = {
        OP_Noop,             /* 0: () */
        OP_IdxGE,            /* 1: (end_constraints && !bRev) */
        OP_IdxLT             /* 2: (end_constraints && bRev) */
      };
      int nEq = pLevel->nEq;
      int isMinQuery = 0;          /* If this is an optimized SELECT min(x).. */
      int regBase;                 /* Base register holding constraint values */
      int r1;                      /* Temp register */







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




|



|
|

|

|


|







2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
        int r1 = sqlite3GetTempReg(pParse);
        sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
        /* sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); */
        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 
      **         optimized:
      **
      **            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,
        0,
        OP_Rewind,           /* 2: (!start_constraints && startEq &&  !bRev) */
        OP_Last,             /* 3: (!start_constraints && startEq &&   bRev) */
        OP_MoveGt,           /* 4: (start_constraints  && !startEq && !bRev) */
        OP_MoveLt,           /* 5: (start_constraints  && !startEq &&  bRev) */
        OP_MoveGe,           /* 6: (start_constraints  &&  startEq && !bRev) */
        OP_MoveLe            /* 7: (start_constraints  &&  startEq &&  bRev) */
      };
      int aEndOp[] = {
        OP_Noop,             /* 0: (!end_constraints) */
        OP_IdxGE,            /* 1: (end_constraints && !bRev) */
        OP_IdxLT             /* 2: (end_constraints && bRev) */
      };
      int nEq = pLevel->nEq;
      int isMinQuery = 0;          /* If this is an optimized SELECT min(x).. */
      int regBase;                 /* Base register holding constraint values */
      int r1;                      /* Temp register */
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
       && (pLevel->flags&WHERE_ORDERBY)
       && (pIdx->nColumn>nEq)
       && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
      ){
        isMinQuery = 1;
      }

      /* Find the inequality constraint terms for the start and end 
      ** of the range. 
      */
      if( pLevel->flags & WHERE_TOP_LIMIT ){
        pRangeEnd = findTerm(&wc, iCur, k, notReady, (WO_LT|WO_LE), pIdx);
      }
      if( pLevel->flags & WHERE_BTM_LIMIT ){
        pRangeStart = findTerm(&wc, iCur, k, notReady, (WO_GT|WO_GE), pIdx);







|







2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
       && (pLevel->flags&WHERE_ORDERBY)
       && (pIdx->nColumn>nEq)
       && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
      ){
        isMinQuery = 1;
      }

      /* Find any inequality constraint terms for the start and end 
      ** of the range. 
      */
      if( pLevel->flags & WHERE_TOP_LIMIT ){
        pRangeEnd = findTerm(&wc, iCur, k, notReady, (WO_LT|WO_LE), pIdx);
      }
      if( pLevel->flags & WHERE_BTM_LIMIT ){
        pRangeStart = findTerm(&wc, iCur, k, notReady, (WO_GT|WO_GE), pIdx);
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
        ptr++;
      }else if( isMinQuery ){
        sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
        ptr++;
        startEq = 0;
        start_constraints = 1;
      }
      sqlite3VdbeAddOp2(v, OP_Affinity, regBase, (int)ptr);
      sqlite3IndexAffinityStr(v, 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);

        ptr++;
      }
      sqlite3VdbeAddOp2(v, OP_Affinity, regBase, (int)ptr);
      sqlite3IndexAffinityStr(v, pIdx);

      /* 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);







|
<










>


<
<







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
        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);
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
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
      /* Record the instruction used to terminate the loop. Disable 
      ** 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 if( pLevel->flags & WHERE_COLUMN_EQ ){
      /* Case 4:  There is an index and all terms of the WHERE clause that
      **          refer to the index using the "==" or "IN" operators.
      */
      int start;
      int nEq = pLevel->nEq;
      int isMinQuery = 0;      /* If this is an optimized SELECT min(x) ... */
      int regBase;             /* Base register of array holding constraints */
      int r1;

      /* Generate code to evaluate all constraint terms using == or IN
      ** and leave the values of those terms on the stack.
      */
      regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1);
      nxt = pLevel->nxt;

      if( (wflags&WHERE_ORDERBY_MIN)!=0
       && (pLevel->flags&WHERE_ORDERBY) 
       && (pIdx->nColumn>nEq)
       && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
      ){
        isMinQuery = 1;
        buildIndexProbe(pParse, nEq, pIdx, regBase, pLevel->iMem);
        sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
        r1 = ++pParse->nMem;
        buildIndexProbe(pParse, nEq+1, pIdx, regBase, r1);
      }else{
        /* Generate a single key that will be used to both start and 
        ** terminate the search
        */
        r1 = pLevel->iMem;
        buildIndexProbe(pParse, nEq, pIdx, regBase, r1);
      }

      /* Generate code (1) to move to the first matching element of the table.
      ** Then generate code (2) that jumps to "nxt" after the cursor is past
      ** the last matching element of the table.  The code (1) is executed
      ** once to initialize the search, the code (2) is executed before each
      ** iteration of the scan to see if the scan has finished. */
      if( bRev ){
        /* Scan in reverse order */
        int op;
        if( isMinQuery ){
          op = OP_MoveLt;
        }else{
          op = OP_MoveLe;
        }
        sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
        start = sqlite3VdbeAddOp3(v, OP_IdxLT, iIdxCur, nxt, pLevel->iMem);
        pLevel->op = OP_Prev;
      }else{
        /* Scan in the forward order */
        int op;
        if( isMinQuery ){
          op = OP_MoveGt;
        }else{
          op = OP_MoveGe;
        }
        sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
        start = sqlite3VdbeAddOp3(v, OP_IdxGE, iIdxCur, nxt, pLevel->iMem);
        sqlite3VdbeChangeP5(v, 1);
        pLevel->op = OP_Next;
      }
      if( !omitTable ){
        r1 = sqlite3GetTempReg(pParse);
        sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
        sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1);  /* Deferred seek */
        sqlite3ReleaseTempReg(pParse, r1);
      }
      pLevel->p1 = iIdxCur;
      pLevel->p2 = start;
    }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;







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







2614
2615
2616
2617
2618
2619
2620







































































2621
2622
2623
2624
2625
2626
2627
      /* Record the instruction used to terminate the loop. Disable 
      ** 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;