From: danielk1977 Date: Fri, 18 Apr 2008 09:01:15 +0000 (+0000) Subject: Allow OP_MoveGt and similar to use an array of registers instead of a serialized... X-Git-Tag: version-3.6.10~1149 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=751de567c14adf5e470f086d1df9d0f13478f11e;p=thirdparty%2Fsqlite.git 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) FossilOrigin-Name: c448f15aa5ed3dec511426775e893efea324faa1 --- diff --git a/manifest b/manifest index bd77d3142e..5a456e3c1a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continuing\sprogress\son\sthe\sjournal_mode\spragma.\s\sIt\sstill\sdoes\snot\swork.\s(CVS\s5027) -D 2008-04-17T20:59:38 +C Allow\sOP_MoveGt\sand\ssimilar\sto\suse\san\sarray\sof\sregisters\sinstead\sof\sa\sserialized\srecord.\sModify\sone\stype\sof\sindex\srange\sscan\sto\suse\sthis.\s(CVS\s5028) +D 2008-04-18T09:01:16 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 25b3282a4ac39388632c2fb0e044ff494d490952 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -174,16 +174,16 @@ F src/update.c 57282dae1ffffaf4aedc3201ed77f8ef09be4f45 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/util.c 943caa4071488b20ed90588f0704c6825f91836b F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30 -F src/vdbe.c e4a3df1221a8ee8025c7132cf8ab6bc88eae4e02 +F src/vdbe.c 6b3a2273255d7527f17a2f4c123bcaa02969ddc0 F src/vdbe.h bfd84bda447f39cb599302c7ec85067dae20453c -F src/vdbeInt.h 0b96efdeecb0803e504bf1c16b198f87c91d6019 +F src/vdbeInt.h 05316345da487b0cf540482576f9ae3337d133cd F src/vdbeapi.c 0e1b5a808bb0e556f2a975eb7d11fd3153e922bf -F src/vdbeaux.c 54fc53eecf270e57957bcc596c2fe452527a8274 +F src/vdbeaux.c ca70c67f853c927d4c1172299578d4b22d4eed50 F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736 F src/vdbemem.c 237e61216381998ff71c6431e5e7bd03386f6225 F src/vtab.c f5e78bf73df3b0c1b53861109c1b2e0800b108cc -F src/where.c 4835f36ba01f663794b96131b81a1ca43ac239fa +F src/where.c e6850aa2fbe655c15914e9b102a20abf2834ab89 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test d56a3ca8acdf761204aff0a2e7aa5eb8e11b31e6 @@ -631,7 +631,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 0d2e258e1a3276e55903ba2ded987f8d8a18cacd -R a3d09c936cfdc9f30d64221d6e47db54 -U drh -Z 6c3e52b390c6e8cd0898e3f15efd7bdb +P 4a72a7bb9c5793cdaf4ee038482053e042d8db54 +R 63ab958aeb1a64fb1b489284d8bf24a2 +U danielk1977 +Z ffb6897ecd3dcda79af541b97309bd4b diff --git a/manifest.uuid b/manifest.uuid index 745026bfb2..83af5c671c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4a72a7bb9c5793cdaf4ee038482053e042d8db54 \ No newline at end of file +c448f15aa5ed3dec511426775e893efea324faa1 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 07bd6b99fc..16cd578b7a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** 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.730 2008/04/15 12:14:22 drh Exp $ +** $Id: vdbe.c,v 1.731 2008/04/18 09:01:16 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -2133,6 +2133,26 @@ op_column_out: break; } +/* Opcode: Affinity P1 P2 * P4 * +** +** Apply affinities to a range of P2 registers starting with P1. +** +** P4 is a string that is P2 characters long. The nth character of the +** string indicates the column affinity that should be used for the nth +** memory cell in the range. +*/ +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 * ** ** Convert P2 registers beginning with P1 into a single entry @@ -2142,7 +2162,7 @@ op_column_out: ** Refer to source code comments for the details of the record ** format. ** -** P4 may be a string that is P1 characters long. The nth character of the +** P4 may be a string that is P2 characters long. The nth character of the ** string indicates the column affinity that should be used for the nth ** field of the index key. ** @@ -2807,13 +2827,17 @@ case OP_Close: { ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe */ -/* Opcode: MoveLe P1 P2 P3 * * +/* Opcode: MoveLe P1 P2 P3 P4 * ** -** 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. +** 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 */ @@ -2848,9 +2872,20 @@ case OP_MoveGt: { /* jump, in3 */ pC->lastRowid = iKey; pC->rowidIsValid = res==0; }else{ - assert( pIn3->flags & MEM_Blob ); - ExpandBlob(pIn3); - rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res); + 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; } @@ -3023,7 +3058,7 @@ case OP_IsUnique: { /* jump, in3 */ break; } } - rc = sqlite3VdbeIdxKeyCompare(pCx, len, (u8*)zKey, &res); + rc = sqlite3VdbeIdxKeyCompare(pCx, 0, len, (u8*)zKey, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res>0 ){ pc = pOp->p2 - 1; @@ -3817,10 +3852,9 @@ case OP_IdxRowid: { /* out2-prerelease */ ** If the P1 index entry is less than the register P3 value ** then jump to P2. Otherwise fall through to the next instruction. ** -** If P5 is non-zero then the -** index taken from register P3 is temporarily increased by -** an epsilon prior to the comparison. This makes the opcode work -** like IdxLE. +** If P5 is non-zero then the index taken from register P3 is temporarily +** increased by an epsilon prior to the comparison. This makes the opcode +** work like IdxLE. */ case OP_IdxLT: /* jump, in3 */ case OP_IdxGE: { /* jump, in3 */ @@ -3832,12 +3866,22 @@ case OP_IdxGE: { /* jump, in3 */ if( (pC = p->apCsr[i])->pCursor!=0 ){ int res; - assert( pIn3->flags & MEM_Blob ); /* Created using OP_MakeRecord */ assert( pC->deferredMoveto==0 ); - ExpandBlob(pIn3); assert( pOp->p5==0 || pOp->p5==1 ); *pC->pIncrKey = pOp->p5; - rc = sqlite3VdbeIdxKeyCompare(pC, pIn3->n, (u8*)pIn3->z, &res); + if( pOp->p4type!=P4_INT32 || pOp->p4.i==0 ){ + assert( pIn3->flags & MEM_Blob ); /* Created using OP_MakeRecord */ + ExpandBlob(pIn3); + rc = sqlite3VdbeIdxKeyCompare(pC, 0, pIn3->n, (u8*)pIn3->z, &res); + }else{ + UnpackedRecord r; + r.pKeyInfo = pC->pKeyInfo; + r.nField = pOp->p4.i; + r.needFree = 0; + r.needDestroy = 0; + r.aMem = &p->aMem[pOp->p3]; + rc = sqlite3VdbeIdxKeyCompare(pC, &r, 0, 0, &res); + } *pC->pIncrKey = 0; if( rc!=SQLITE_OK ){ break; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 7f99daae93..8260d999f5 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -387,7 +387,7 @@ int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); -int sqlite3VdbeIdxKeyCompare(Cursor*,int,const unsigned char*,int*); +int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord *,int,const unsigned char*,int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3VdbeIdxRowidLen(const u8*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 1752867665..903c12f02e 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2401,6 +2401,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ */ int sqlite3VdbeIdxKeyCompare( Cursor *pC, /* The cursor to compare against */ + UnpackedRecord *pUnpacked, int nKey, const u8 *pKey, /* The key to compare */ int *res /* Write the comparison result here */ ){ @@ -2425,13 +2426,19 @@ int sqlite3VdbeIdxKeyCompare( return rc; } lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z); - pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey, + if( !pUnpacked ){ + pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey, zSpace, sizeof(zSpace)); + }else{ + pRec = pUnpacked; + } if( pRec==0 ){ return SQLITE_NOMEM; } *res = sqlite3VdbeRecordCompare(m.n-lenRowid, m.z, pRec); - sqlite3VdbeDeleteUnpackedRecord(pRec); + if( !pUnpacked ){ + sqlite3VdbeDeleteUnpackedRecord(pRec); + } sqlite3VdbeMemRelease(&m); return SQLITE_OK; } diff --git a/src/where.c b/src/where.c index 3b7df014e4..0ccc601663 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** 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.299 2008/04/17 19:14:02 drh Exp $ +** $Id: where.c,v 1.300 2008/04/18 09:01:16 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -2475,36 +2475,40 @@ WhereInfo *sqlite3WhereBegin( ** constraints but an index is selected anyway, in order ** to force the output order to conform to an ORDER BY. */ - int start; + 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 topEq=0; /* True if top limit uses ==. False is strictly < */ - int btmEq=0; /* True if btm limit uses ==. False if strictly > */ - int topOp, btmOp; /* Operators for the top and bottom search bounds */ - int testOp; - int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; - int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; - int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */ - int regBase; /* Base register holding constraint values */ - int r1; /* Temp register */ + int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */ + int regBase; /* Base register holding constraint values */ + 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 level the values of those terms on the stack. + ** and store the values of those terms in an array of registers + ** starting at regBase. */ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2); - - /* Figure out what comparison operators to use for top and bottom - ** search bounds. For an ascending index, the bottom bound is a > or >= - ** operator and the top bound is a < or <= operator. For a descending - ** index the operators are reversed. - */ - if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){ - topOp = WO_LT|WO_LE; - btmOp = WO_GT|WO_GE; - }else{ - topOp = WO_GT|WO_GE; - btmOp = WO_LT|WO_LE; - SWAP(int, topLimit, btmLimit); - } + nxt = pLevel->nxt; /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." @@ -2522,121 +2526,95 @@ WhereInfo *sqlite3WhereBegin( isMinQuery = 1; } - /* Generate the termination key. This is the key value that - ** will end the search. There is no termination key if there - ** are no equality terms and no "X<..." term. - ** - ** 2002-Dec-04: On a reverse-order scan, the so-called "termination" - ** key computed here really ends up being the start key. + /* Find the inequality constraint terms for the start and end + ** of the range. */ - nxt = pLevel->nxt; - if( topLimit ){ - Expr *pX; - int k = pIdx->aiColumn[nEq]; - pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx); - assert( pTerm!=0 ); - pX = pTerm->pExpr; - assert( (pTerm->flags & TERM_CODED)==0 ); - sqlite3ExprCode(pParse, pX->pRight, regBase+nEq); - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); - topEq = pTerm->eOperator & (WO_LE|WO_GE); - disableTerm(pLevel, pTerm); - testOp = OP_IdxGE; - }else{ - testOp = nEq>0 ? OP_IdxGE : OP_Noop; - topEq = 1; + if( pLevel->flags & WHERE_TOP_LIMIT ){ + pRangeEnd = findTerm(&wc, iCur, k, notReady, (WO_LT|WO_LE), pIdx); } - if( testOp!=OP_Noop || (isMinQuery&&bRev) ){ - int nCol = nEq + topLimit; - if( isMinQuery && bRev && !topLimit ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); - nCol++; - topEq = 0; - } - buildIndexProbe(pParse, nCol, pIdx, regBase, pLevel->iMem); - if( bRev ){ - int op = topEq ? OP_MoveLe : OP_MoveLt; - sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem); - } - }else if( bRev ){ - sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk); + if( pLevel->flags & WHERE_BTM_LIMIT ){ + pRangeStart = findTerm(&wc, iCur, k, notReady, (WO_GT|WO_GE), pIdx); } - - /* Generate the start key. This is the key that defines the lower - ** bound on the search. There is no start key if there are no - ** equality terms and if there is no "X>..." term. In - ** that case, generate a "Rewind" instruction in place of the - ** start key search. - ** - ** 2002-Dec-04: In the case of a reverse-order search, the so-called - ** "start" key really ends up being used as the termination key. + + /* 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( btmLimit ){ - Expr *pX; - int k = pIdx->aiColumn[nEq]; - pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx); - assert( pTerm!=0 ); - pX = pTerm->pExpr; - assert( (pTerm->flags & TERM_CODED)==0 ); - sqlite3ExprCode(pParse, pX->pRight, regBase+nEq); - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); - btmEq = pTerm->eOperator & (WO_LE|WO_GE); - disableTerm(pLevel, pTerm); - }else{ - btmEq = 1; + if( bRev==((pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)?1:0) ){ + SWAP(WhereTerm *, pRangeEnd, pRangeStart); } - if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){ - int nCol = nEq + btmLimit; - if( isMinQuery && !bRev && !btmLimit ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); - nCol++; - btmEq = 0; - } - if( bRev ){ - r1 = pLevel->iMem; - testOp = OP_IdxLT; - }else{ - r1 = sqlite3GetTempReg(pParse); - } - buildIndexProbe(pParse, nCol, pIdx, regBase, r1); - if( !bRev ){ - int op = btmEq ? OP_MoveGe : OP_MoveGt; - sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); - sqlite3ReleaseTempReg(pParse, r1); + + 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; } - }else if( bRev ){ - testOp = OP_Noop; - }else{ - sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, brk); + 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; } + 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); - /* Generate the the top of the loop. If there is a termination - ** key we have to test for that key and abort at the top of the - ** loop. + /* Load the value for the inequality constraint at the end of the + ** range (if any). */ - start = sqlite3VdbeCurrentAddr(v); - if( testOp!=OP_Noop ){ - sqlite3VdbeAddOp3(v, testOp, iIdxCur, nxt, pLevel->iMem); - if( (topEq && !bRev) || (!btmEq && bRev) ){ - sqlite3VdbeChangeP5(v, 1); - } + 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); + 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( topLimit | btmLimit ){ + 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 ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */ } sqlite3ReleaseTempReg(pParse, r1); - /* Record the instruction used to terminate the loop. + /* 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; - pLevel->p2 = start; + 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.