From 6df2acd216d7902c02db8738b8e1e74832a6f50b Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 28 Dec 2008 16:55:25 +0000 Subject: [PATCH] Simplify the VM code that implements WHERE claues. (CVS 6067) FossilOrigin-Name: fa95f843e179a38f663978d675607c4c3037928d --- manifest | 16 +++++------ manifest.uuid | 2 +- src/sqliteInt.h | 15 ++++++----- src/where.c | 71 ++++++++++++++++++++++++++++++------------------- 4 files changed, 61 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index 82ed58fb8a..2877586851 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\ssavepoint\sand\sincremental-vacuum.\s(CVS\s6066) -D 2008-12-27T15:23:13 +C Simplify\sthe\sVM\scode\sthat\simplements\sWHERE\sclaues.\s(CVS\s6067) +D 2008-12-28T16:55:25 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -158,7 +158,7 @@ F src/select.c 6c2a5675c21bef11d8160f3dc97e1adfbf26bbb9 F src/shell.c 65d19f8996a160f288087e31810f24025439c62a F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 -F src/sqliteInt.h 2362e805d375c547f6d91d4732da8f93e1e668af +F src/sqliteInt.h 85c72545ac3195bb7d9aefc8377f91123594c59c F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8 @@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935 F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43 F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d -F src/where.c b273a232aa6e7616bb6025a80276c8aff8df2b22 +F src/where.c f41330e71f3dde12cc6631ae9f75c9869b92c32b F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911 @@ -686,7 +686,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P a1b1f6cd7d2c060bd75ce39347e1220b872806ed -R 1a9ec7089b4909b30df347c1e2ee32e6 -U danielk1977 -Z 75549ad37a08cbb85b58f7a2c8f6829a +P 08352f9ea9d2a1759320efc46e418079000855cb +R b27114cf38ee45f9d895c0015e5cf61b +U drh +Z 5701aac5e9c50a29a7e1c4535e66ab21 diff --git a/manifest.uuid b/manifest.uuid index dd8c9e131b..dcd41005a3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -08352f9ea9d2a1759320efc46e418079000855cb \ No newline at end of file +fa95f843e179a38f663978d675607c4c3037928d \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 221813b818..735ed92e61 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** 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_ #define _SQLITEINT_H_ @@ -1595,11 +1595,13 @@ struct WhereLevel { /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin(). */ -#define WHERE_ORDERBY_NORMAL 0x000 /* No-op */ -#define WHERE_ORDERBY_MIN 0x001 /* ORDER BY processing for min() func */ -#define WHERE_ORDERBY_MAX 0x002 /* ORDER BY processing for max() func */ -#define WHERE_ONEPASS_DESIRED 0x004 /* Want to do one-pass UPDATE/DELETE */ -#define WHERE_FILL_ROWSET 0x008 /* Save results in a RowSet object */ +#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ +#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ +#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ +#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ +#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 @@ -1610,6 +1612,7 @@ struct WhereLevel { */ struct WhereInfo { 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 */ int regRowSet; /* Store rowids in this rowset if >=0 */ SrcList *pTabList; /* List of tables in the join */ diff --git a/src/where.c b/src/where.c index 9b317aeee8..d0a5c531e8 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.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" @@ -26,7 +26,7 @@ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) int sqlite3WhereTrace = 0; #endif -#if 1 +#if 0 # define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X #else # define WHERETRACE(X) @@ -2111,8 +2111,8 @@ static int codeEqualityTerm( ** The index has as many as three equality constraints, but in this ** example, the third "c" value is an inequality. So only two ** 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 -** on the stack - a is the deepest and b the shallowest. +** a==5 and b IN (1,2,3). The current values for a and b will be stored +** 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 ** 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 */ int j; /* Loop counter */ int regBase; /* Base register */ + int nReg; /* Number of registers to allocate */ /* This module is only called on query plans that use an index. */ assert( pLevel->plan.wsFlags & WHERE_INDEXED ); pIdx = pLevel->plan.u.pIdx; /* 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; - pParse->nMem += pLevel->plan.nEq + 1 + nExtraReg; + nReg = pLevel->plan.nEq + nExtraReg; + pParse->nMem += nReg; /* Evaluate the equality constraints */ @@ -2163,7 +2162,12 @@ static int codeAllEqualityTerms( assert( (pTerm->wtFlags & TERM_CODED)==0 ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j); if( r1!=regBase+j ){ - sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); + if( nReg==1 ){ + sqlite3ReleaseTempReg(pParse, regBase); + regBase = r1; + }else{ + sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); + } } testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IN ); @@ -2464,19 +2468,13 @@ static Bitmask codeOneLoopStart( int nConstraint; /* Number of constraint terms */ Index *pIdx; /* The index we will be using */ 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; iIdxCur = pLevel->iIdxCur; 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 ** was passed to this function to implement a "SELECT min(x) ..." ** 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->a[0].pExpr->iColumn==pIdx->aiColumn[nEq] ); */ isMinQuery = 1; + nExtraReg = 1; } /* Find any inequality constraint terms for the start and end @@ -2499,11 +2498,21 @@ static Bitmask codeOneLoopStart( */ if( pLevel->plan.wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = findTerm(pWC, iCur, k, notReady, (WO_LT|WO_LE), pIdx); + nExtraReg = 1; } if( pLevel->plan.wsFlags & WHERE_BTM_LIMIT ){ 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 ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). @@ -2568,9 +2577,11 @@ static Bitmask codeOneLoopStart( testcase( op==OP_Noop ); testcase( op==OP_IdxGE ); testcase( op==OP_IdxLT ); - sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase, - SQLITE_INT_TO_PTR(nConstraint), P4_INT32); - sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0); + if( op!=OP_Noop ){ + sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase, + SQLITE_INT_TO_PTR(nConstraint), P4_INT32); + sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0); + } /* If there are inequality constraints, check that the value ** of the table column that the inequality contrains is not NULL. @@ -2661,9 +2672,9 @@ static Bitmask codeOneLoopStart( WhereInfo *pSubWInfo; if( pOrTerm->leftCursor!=iCur ) continue; pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0, - WHERE_FILL_ROWSET, regOrRowset); + WHERE_FILL_ROWSET | WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE, + regOrRowset); if( pSubWInfo ){ - pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY; sqlite3WhereEnd(pSubWInfo); } } @@ -2935,6 +2946,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->iBreak = sqlite3VdbeMakeLabel(v); pWInfo->regRowSet = (wctrlFlags & WHERE_FILL_ROWSET) ? regRowSet : -1; pWInfo->pWC = pWC = (WhereClause*)&pWInfo->a[pWInfo->nLevel]; + pWInfo->wctrlFlags = wctrlFlags; pMaskSet = (WhereMaskSet*)&pWC[1]; /* Split the WHERE clause into separate subexpressions where each @@ -3164,7 +3176,8 @@ WhereInfo *sqlite3WhereBegin( (const char*)pTab->pVtab, P4_VTAB); }else #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; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); if( !pWInfo->okOnePass && pTab->nColpTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue; - if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){ - sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); - } - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ - sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); + if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){ + if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){ + sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); + } + if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ + sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); + } } /* If this scan uses an index, make code substitutions to read data -- 2.47.2