mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-08 03:22:21 +03:00
Simplify the VM code that implements WHERE claues. (CVS 6067)
FossilOrigin-Name: fa95f843e179a38f663978d675607c4c3037928d
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\sproblem\swith\ssavepoint\sand\sincremental-vacuum.\s(CVS\s6066)
|
C Simplify\sthe\sVM\scode\sthat\simplements\sWHERE\sclaues.\s(CVS\s6067)
|
||||||
D 2008-12-27T15:23:13
|
D 2008-12-28T16:55:25
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
|
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -158,7 +158,7 @@ F src/select.c 6c2a5675c21bef11d8160f3dc97e1adfbf26bbb9
|
|||||||
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
|
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
|
||||||
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
|
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
|
||||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||||
F src/sqliteInt.h 2362e805d375c547f6d91d4732da8f93e1e668af
|
F src/sqliteInt.h 85c72545ac3195bb7d9aefc8377f91123594c59c
|
||||||
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
||||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||||
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
|
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
|
||||||
@@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
|
|||||||
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
|
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
|
||||||
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
||||||
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
|
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
|
||||||
F src/where.c b273a232aa6e7616bb6025a80276c8aff8df2b22
|
F src/where.c f41330e71f3dde12cc6631ae9f75c9869b92c32b
|
||||||
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
||||||
@@ -686,7 +686,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P a1b1f6cd7d2c060bd75ce39347e1220b872806ed
|
P 08352f9ea9d2a1759320efc46e418079000855cb
|
||||||
R 1a9ec7089b4909b30df347c1e2ee32e6
|
R b27114cf38ee45f9d895c0015e5cf61b
|
||||||
U danielk1977
|
U drh
|
||||||
Z 75549ad37a08cbb85b58f7a2c8f6829a
|
Z 5701aac5e9c50a29a7e1c4535e66ab21
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
08352f9ea9d2a1759320efc46e418079000855cb
|
fa95f843e179a38f663978d675607c4c3037928d
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.815 2008/12/23 23:56:22 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.816 2008/12/28 16:55:25 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1595,11 +1595,13 @@ struct WhereLevel {
|
|||||||
/*
|
/*
|
||||||
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
|
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
|
||||||
*/
|
*/
|
||||||
#define WHERE_ORDERBY_NORMAL 0x000 /* No-op */
|
#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */
|
||||||
#define WHERE_ORDERBY_MIN 0x001 /* ORDER BY processing for min() func */
|
#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */
|
||||||
#define WHERE_ORDERBY_MAX 0x002 /* ORDER BY processing for max() func */
|
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
|
||||||
#define WHERE_ONEPASS_DESIRED 0x004 /* Want to do one-pass UPDATE/DELETE */
|
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
|
||||||
#define WHERE_FILL_ROWSET 0x008 /* Save results in a RowSet object */
|
#define WHERE_FILL_ROWSET 0x0008 /* Save results in a RowSet object */
|
||||||
|
#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
|
||||||
|
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The WHERE clause processing routine has two halves. The
|
** The WHERE clause processing routine has two halves. The
|
||||||
@@ -1610,6 +1612,7 @@ struct WhereLevel {
|
|||||||
*/
|
*/
|
||||||
struct WhereInfo {
|
struct WhereInfo {
|
||||||
Parse *pParse; /* Parsing and code generating context */
|
Parse *pParse; /* Parsing and code generating context */
|
||||||
|
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
|
||||||
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
|
||||||
int regRowSet; /* Store rowids in this rowset if >=0 */
|
int regRowSet; /* Store rowids in this rowset if >=0 */
|
||||||
SrcList *pTabList; /* List of tables in the join */
|
SrcList *pTabList; /* List of tables in the join */
|
||||||
|
|||||||
53
src/where.c
53
src/where.c
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.344 2008/12/24 11:25:40 danielk1977 Exp $
|
** $Id: where.c,v 1.345 2008/12/28 16:55:25 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||||
int sqlite3WhereTrace = 0;
|
int sqlite3WhereTrace = 0;
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 0
|
||||||
# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X
|
# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X
|
||||||
#else
|
#else
|
||||||
# define WHERETRACE(X)
|
# define WHERETRACE(X)
|
||||||
@@ -2111,8 +2111,8 @@ static int codeEqualityTerm(
|
|||||||
** The index has as many as three equality constraints, but in this
|
** The index has as many as three equality constraints, but in this
|
||||||
** example, the third "c" value is an inequality. So only two
|
** example, the third "c" value is an inequality. So only two
|
||||||
** constraints are coded. This routine will generate code to evaluate
|
** constraints are coded. This routine will generate code to evaluate
|
||||||
** a==5 and b IN (1,2,3). The current values for a and b will be left
|
** a==5 and b IN (1,2,3). The current values for a and b will be stored
|
||||||
** on the stack - a is the deepest and b the shallowest.
|
** in consecutive registers and the index of the first register is returned.
|
||||||
**
|
**
|
||||||
** In the example above nEq==2. But this subroutine works for any value
|
** In the example above nEq==2. But this subroutine works for any value
|
||||||
** of nEq including 0. If nEq==0, this routine is nearly a no-op.
|
** of nEq including 0. If nEq==0, this routine is nearly a no-op.
|
||||||
@@ -2139,18 +2139,17 @@ static int codeAllEqualityTerms(
|
|||||||
WhereTerm *pTerm; /* A single constraint term */
|
WhereTerm *pTerm; /* A single constraint term */
|
||||||
int j; /* Loop counter */
|
int j; /* Loop counter */
|
||||||
int regBase; /* Base register */
|
int regBase; /* Base register */
|
||||||
|
int nReg; /* Number of registers to allocate */
|
||||||
|
|
||||||
/* This module is only called on query plans that use an index. */
|
/* This module is only called on query plans that use an index. */
|
||||||
assert( pLevel->plan.wsFlags & WHERE_INDEXED );
|
assert( pLevel->plan.wsFlags & WHERE_INDEXED );
|
||||||
pIdx = pLevel->plan.u.pIdx;
|
pIdx = pLevel->plan.u.pIdx;
|
||||||
|
|
||||||
/* Figure out how many memory cells we will need then allocate them.
|
/* Figure out how many memory cells we will need then allocate them.
|
||||||
** We always need at least one used to store the loop terminator
|
|
||||||
** value. If there are IN operators we'll need one for each == or
|
|
||||||
** IN constraint.
|
|
||||||
*/
|
*/
|
||||||
regBase = pParse->nMem + 1;
|
regBase = pParse->nMem + 1;
|
||||||
pParse->nMem += pLevel->plan.nEq + 1 + nExtraReg;
|
nReg = pLevel->plan.nEq + nExtraReg;
|
||||||
|
pParse->nMem += nReg;
|
||||||
|
|
||||||
/* Evaluate the equality constraints
|
/* Evaluate the equality constraints
|
||||||
*/
|
*/
|
||||||
@@ -2163,8 +2162,13 @@ static int codeAllEqualityTerms(
|
|||||||
assert( (pTerm->wtFlags & TERM_CODED)==0 );
|
assert( (pTerm->wtFlags & TERM_CODED)==0 );
|
||||||
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
||||||
if( r1!=regBase+j ){
|
if( r1!=regBase+j ){
|
||||||
|
if( nReg==1 ){
|
||||||
|
sqlite3ReleaseTempReg(pParse, regBase);
|
||||||
|
regBase = r1;
|
||||||
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
|
sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
testcase( pTerm->eOperator & WO_ISNULL );
|
testcase( pTerm->eOperator & WO_ISNULL );
|
||||||
testcase( pTerm->eOperator & WO_IN );
|
testcase( pTerm->eOperator & WO_IN );
|
||||||
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
|
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
|
||||||
@@ -2464,19 +2468,13 @@ static Bitmask codeOneLoopStart(
|
|||||||
int nConstraint; /* Number of constraint terms */
|
int nConstraint; /* Number of constraint terms */
|
||||||
Index *pIdx; /* The index we will be using */
|
Index *pIdx; /* The index we will be using */
|
||||||
int iIdxCur; /* The VDBE cursor for the index */
|
int iIdxCur; /* The VDBE cursor for the index */
|
||||||
int op;
|
int nExtraReg = 0; /* Number of extra registers needed */
|
||||||
|
int op; /* Instruction opcode */
|
||||||
|
|
||||||
pIdx = pLevel->plan.u.pIdx;
|
pIdx = pLevel->plan.u.pIdx;
|
||||||
iIdxCur = pLevel->iIdxCur;
|
iIdxCur = pLevel->iIdxCur;
|
||||||
k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
|
k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
|
||||||
|
|
||||||
/* 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, pWC, notReady, 2);
|
|
||||||
addrNxt = pLevel->addrNxt;
|
|
||||||
|
|
||||||
/* If this loop satisfies a sort order (pOrderBy) request that
|
/* If this loop satisfies a sort order (pOrderBy) request that
|
||||||
** was passed to this function to implement a "SELECT min(x) ..."
|
** was passed to this function to implement a "SELECT min(x) ..."
|
||||||
** query, then the caller will only allow the loop to run for
|
** query, then the caller will only allow the loop to run for
|
||||||
@@ -2492,6 +2490,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
/* assert( pOrderBy->nExpr==1 ); */
|
/* assert( pOrderBy->nExpr==1 ); */
|
||||||
/* assert( pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq] ); */
|
/* assert( pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq] ); */
|
||||||
isMinQuery = 1;
|
isMinQuery = 1;
|
||||||
|
nExtraReg = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find any inequality constraint terms for the start and end
|
/* Find any inequality constraint terms for the start and end
|
||||||
@@ -2499,11 +2498,21 @@ static Bitmask codeOneLoopStart(
|
|||||||
*/
|
*/
|
||||||
if( pLevel->plan.wsFlags & WHERE_TOP_LIMIT ){
|
if( pLevel->plan.wsFlags & WHERE_TOP_LIMIT ){
|
||||||
pRangeEnd = findTerm(pWC, iCur, k, notReady, (WO_LT|WO_LE), pIdx);
|
pRangeEnd = findTerm(pWC, iCur, k, notReady, (WO_LT|WO_LE), pIdx);
|
||||||
|
nExtraReg = 1;
|
||||||
}
|
}
|
||||||
if( pLevel->plan.wsFlags & WHERE_BTM_LIMIT ){
|
if( pLevel->plan.wsFlags & WHERE_BTM_LIMIT ){
|
||||||
pRangeStart = findTerm(pWC, iCur, k, notReady, (WO_GT|WO_GE), pIdx);
|
pRangeStart = findTerm(pWC, iCur, k, notReady, (WO_GT|WO_GE), pIdx);
|
||||||
|
nExtraReg = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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, pWC, notReady, nExtraReg);
|
||||||
|
addrNxt = pLevel->addrNxt;
|
||||||
|
|
||||||
|
|
||||||
/* If we are doing a reverse order scan on an ascending index, or
|
/* If we are doing a reverse order scan on an ascending index, or
|
||||||
** a forward order scan on a descending index, interchange the
|
** a forward order scan on a descending index, interchange the
|
||||||
** start and end terms (pRangeStart and pRangeEnd).
|
** start and end terms (pRangeStart and pRangeEnd).
|
||||||
@@ -2568,9 +2577,11 @@ static Bitmask codeOneLoopStart(
|
|||||||
testcase( op==OP_Noop );
|
testcase( op==OP_Noop );
|
||||||
testcase( op==OP_IdxGE );
|
testcase( op==OP_IdxGE );
|
||||||
testcase( op==OP_IdxLT );
|
testcase( op==OP_IdxLT );
|
||||||
|
if( op!=OP_Noop ){
|
||||||
sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
|
sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
|
||||||
SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
|
SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
|
||||||
sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0);
|
sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0);
|
||||||
|
}
|
||||||
|
|
||||||
/* If there are inequality constraints, check that the value
|
/* If there are inequality constraints, check that the value
|
||||||
** of the table column that the inequality contrains is not NULL.
|
** of the table column that the inequality contrains is not NULL.
|
||||||
@@ -2661,9 +2672,9 @@ static Bitmask codeOneLoopStart(
|
|||||||
WhereInfo *pSubWInfo;
|
WhereInfo *pSubWInfo;
|
||||||
if( pOrTerm->leftCursor!=iCur ) continue;
|
if( pOrTerm->leftCursor!=iCur ) continue;
|
||||||
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
|
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
|
||||||
WHERE_FILL_ROWSET, regOrRowset);
|
WHERE_FILL_ROWSET | WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE,
|
||||||
|
regOrRowset);
|
||||||
if( pSubWInfo ){
|
if( pSubWInfo ){
|
||||||
pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY;
|
|
||||||
sqlite3WhereEnd(pSubWInfo);
|
sqlite3WhereEnd(pSubWInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2935,6 +2946,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
||||||
pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
|
pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1;
|
||||||
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
|
pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel];
|
||||||
|
pWInfo->wctrlFlags = wctrlFlags;
|
||||||
pMaskSet = (WhereMaskSet*)&pWC[1];
|
pMaskSet = (WhereMaskSet*)&pWC[1];
|
||||||
|
|
||||||
/* Split the WHERE clause into separate subexpressions where each
|
/* Split the WHERE clause into separate subexpressions where each
|
||||||
@@ -3164,7 +3176,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
(const char*)pTab->pVtab, P4_VTAB);
|
(const char*)pTab->pVtab, P4_VTAB);
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
|
||||||
|
&& (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
|
||||||
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
|
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
|
||||||
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
||||||
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
|
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
|
||||||
@@ -3321,12 +3334,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
Table *pTab = pTabItem->pTab;
|
Table *pTab = pTabItem->pTab;
|
||||||
assert( pTab!=0 );
|
assert( pTab!=0 );
|
||||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
||||||
|
if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
|
||||||
if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
||||||
}
|
}
|
||||||
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If this scan uses an index, make code substitutions to read data
|
/* If this scan uses an index, make code substitutions to read data
|
||||||
** from the index in preference to the table. Sometimes, this means
|
** from the index in preference to the table. Sometimes, this means
|
||||||
|
|||||||
Reference in New Issue
Block a user