From: drh Date: Sat, 12 Jan 2008 19:03:48 +0000 (+0000) Subject: Continuing work toward converting the VM to a register machine. (CVS 4708) X-Git-Tag: version-3.6.10~1469 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2dcef11bb9c6f6b8ac158852e9a4c237068f01e3;p=thirdparty%2Fsqlite.git Continuing work toward converting the VM to a register machine. (CVS 4708) FossilOrigin-Name: 426f31ecdd05d1179a2e49c2ca1666011cede9c6 --- diff --git a/manifest b/manifest index 91864257a6..4f67a8b482 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continuing\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister\smachine.\s(CVS\s4707) -D 2008-01-12T12:48:08 +C Continuing\swork\stoward\sconverting\sthe\sVM\sto\sa\sregister\smachine.\s(CVS\s4708) +D 2008-01-12T19:03:49 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -80,7 +80,7 @@ F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04 F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1 -F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2 +F src/attach.c 71f5c886004a9740fc6e6033d4e1ce0517ab6574 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef @@ -92,7 +92,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c 68bcc07517c763cc7601be45d60084bc11ee0212 +F src/expr.c 14130c27fba6fa3c14dcfc4891c534a8ee71cc3c F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 @@ -131,12 +131,12 @@ F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da -F src/select.c 9e3c65ca3d2508b585b6786dbcbe6cd65560b013 +F src/select.c fc9cebb2033a84b31472405114ad36d73c30b967 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h b143c53760aeb4feeb4eaf8cb10eb26ad5b6c89e +F src/sqliteInt.h c3f43826e48b0d2928b9e6fa3aca887317285392 F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf @@ -168,7 +168,7 @@ F src/update.c aad823f97a930e6982264299863837d4c6107d3b F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c 20bd088657280d75b630d299c59cdb3c6a5c9b9e +F src/vdbe.c a05947fba057311149cb0635cccdee9bed42f3cb F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346 F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c @@ -177,7 +177,7 @@ F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c -F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e +F src/where.c 27e40d32b7b47e70db9ac61b91a3a46c8dc6b47d F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba @@ -314,7 +314,7 @@ F test/fts3ao.test 0aa29dd4fc1c8d46b1f7cfe5926f7ac97551bea9 F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa F test/fts3b.test b3a25180a633873d37d86e1ccd00ed690d37237a F test/fts3near.test 2d4dadcaac5025ab65bb87e66c45f39e92966194 -F test/func.test 4d54202f6a1c8498444d9efe460851b02a1e8e4f +F test/func.test 307b335a47a555bc1e5df94d7f4d6172df25f944 F test/fuzz.test 62fc19dd36a427777fd671b569df07166548628a F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb F test/fuzz_common.tcl ff4bc2dfc465f6878f8e2d819620914365382731 @@ -606,7 +606,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 4744257d3cd2dd96485fde6d9f60542714383421 -R 9fded3f0e818ece501c0ececcbd26a94 +P a6dddebcc5ccbbf3009c9d06163a8b59036331de +R 537e4808d9b23703b914b666ccd36884 U drh -Z fe475f28d0df336b5a859493e9293538 +Z 1569ded7274b37b8c39c0600e4142054 diff --git a/manifest.uuid b/manifest.uuid index 992dde0d9b..85bc50ea1d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a6dddebcc5ccbbf3009c9d06163a8b59036331de \ No newline at end of file +426f31ecdd05d1179a2e49c2ca1666011cede9c6 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 7519546683..20eb93bc6e 100644 --- a/src/attach.c +++ b/src/attach.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.67 2008/01/09 23:04:12 drh Exp $ +** $Id: attach.c,v 1.68 2008/01/12 19:03:49 drh Exp $ */ #include "sqliteInt.h" @@ -297,6 +297,7 @@ static void codeAttach( Vdbe *v; FuncDef *pFunc; sqlite3* db = pParse->db; + int regArgs; #ifndef SQLITE_OMIT_AUTHORIZATION assert( db->mallocFailed || pAuthArg ); @@ -326,13 +327,14 @@ static void codeAttach( } v = sqlite3GetVdbe(pParse); - sqlite3ExprCode(pParse, pFilename, 0); - sqlite3ExprCode(pParse, pDbname, 0); - sqlite3ExprCode(pParse, pKey, 0); + regArgs = sqlite3GetTempRange(pParse, nFunc); + sqlite3ExprCode(pParse, pFilename, regArgs); + sqlite3ExprCode(pParse, pDbname, regArgs+1); + sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ - sqlite3VdbeAddOp0(v, OP_Function); + sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs); sqlite3VdbeChangeP5(v, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); diff --git a/src/expr.c b/src/expr.c index 2d333f74a3..9f27266571 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.343 2008/01/12 12:48:08 drh Exp $ +** $Id: expr.c,v 1.344 2008/01/12 19:03:49 drh Exp $ */ #include "sqliteInt.h" #include @@ -1930,30 +1930,26 @@ void sqlite3ExprCodeGetColumn( /* ** Generate code into the current Vdbe to evaluate the given -** expression and leaves the result in a register on on the stack. +** expression. Attempt to store the results in register "target". +** Return the register where results are stored. ** -** If the target register number is negative, allocate a new -** register to store the result. If the target register number -** is zero then push the result onto the stack. Return the target -** register number regardless. -** -** This code depends on the fact that certain token values (ex: TK_EQ) -** are the same as opcode values (ex: OP_Eq) that implement the corresponding -** operation. Special comments in vdbe.c and the mkopcodeh.awk script in -** the make process cause these values to align. Assert()s in the code -** below verify that the numbers are aligned correctly. +** With this routine, there is no guaranteed that results will +** be stored in target. The result might be stored in some other +** register if it is convenient to do so. The calling function +** must check the return code and move the results to the desired +** register. */ -int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ - Vdbe *v = pParse->pVdbe; - int op; - int inReg = 0; - int origTarget = target; +static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ + Vdbe *v = pParse->pVdbe; /* The VM under construction */ + int op; /* The opcode being coded */ + int inReg = target; /* Results stored in register inReg */ + int regFree1 = 0; /* If non-zero free this temporary register */ + int regFree2 = 0; /* If non-zero free this temporary register */ + int r1, r2, r3; /* Various register numbers */ assert( v!=0 || pParse->db->mallocFailed ); + assert( target>=0 ); if( v==0 ) return 0; - if( target<0 ){ - target = ++pParse->nMem; - } if( pExpr==0 ){ op = TK_NULL; @@ -1971,7 +1967,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx, pCol->iSorterColumn, target); - inReg = target; break; } /* Otherwise, fall thru into the TK_COLUMN case */ @@ -1984,30 +1979,25 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ }else{ sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target); - inReg = target; } break; } case TK_INTEGER: { codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target); - inReg = target; break; } case TK_FLOAT: { codeReal(v, (char*)pExpr->token.z, pExpr->token.n, 0, target); - inReg = target; break; } case TK_STRING: { sqlite3DequoteExpr(pParse->db, pExpr); sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0, (char*)pExpr->token.z, pExpr->token.n); - inReg = target; break; } case TK_NULL: { sqlite3VdbeAddOp2(v, OP_Null, 0, target); - inReg = target; break; } #ifndef SQLITE_OMIT_BLOB_LITERAL @@ -2022,7 +2012,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ z = ""; } sqlite3VdbeAddOp4(v, op, 0, target, 0, z, n); - inReg = target; break; } #endif @@ -2031,7 +2020,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ if( pExpr->token.n>1 ){ sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n); } - inReg = target; break; } case TK_REGISTER: { @@ -2042,7 +2030,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, to_op; - sqlite3ExprCode(pParse, pExpr->pLeft, target); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); aff = sqlite3AffinityType(&pExpr->token); to_op = aff - SQLITE_AFF_TEXT + OP_ToText; assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT ); @@ -2050,8 +2038,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); - sqlite3VdbeAddOp1(v, to_op, target); - inReg = target; + sqlite3VdbeAddOp1(v, to_op, inReg); break; } #endif /* SQLITE_OMIT_CAST */ @@ -2061,20 +2048,17 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_GE: case TK_NE: case TK_EQ: { - int r1, r2; assert( TK_LT==OP_Lt ); assert( TK_LE==OP_Le ); assert( TK_GT==OP_Gt ); assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); - if( target>0 ){ - inReg = target; - }else{ + if( target==0 ){ inReg = ++pParse->nMem; } - r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); - r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); break; @@ -2091,7 +2075,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { - int r1, r2; assert( TK_AND==OP_And ); assert( TK_OR==OP_Or ); assert( TK_PLUS==OP_Add ); @@ -2103,10 +2086,9 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); - r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); - r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp3(v, op, r2, r1, target); - inReg = target; break; } case TK_UMINUS: { @@ -2120,10 +2102,10 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ codeInteger(v, (char*)p->z, p->n, 1, target); } }else{ - int r1 = ++pParse->nMem; + regFree1 = r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Integer, 0, r1); - sqlite3ExprCode(pParse, pExpr->pLeft, target); - sqlite3VdbeAddOp3(v, OP_Subtract, target, r1, target); + r2 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); } inReg = target; break; @@ -2132,8 +2114,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3VdbeAddOp0(v, op); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + sqlite3VdbeAddOp1(v, op, inReg); break; } case TK_ISNULL: @@ -2142,11 +2124,10 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - addr = sqlite3VdbeAddOp0(v, op); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + addr = sqlite3VdbeAddOp1(v, op, r1); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); - inReg = target; break; } case TK_AGG_FUNCTION: { @@ -2178,7 +2159,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( pDef!=0 ); if( pList ){ nExpr = pList->nExpr; - sqlite3ExprCodeExprList(pParse, pList, 0); + r1 = sqlite3GetTempRange(pParse, nExpr); + sqlite3ExprCodeExprList(pParse, pList, r1); }else{ nExpr = 0; } @@ -2213,9 +2195,12 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp4(v, OP_Function, constMask, 0, 0, + sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, nExpr); + if( nExpr ){ + sqlite3ReleaseTempRange(pParse, r1, nExpr); + } break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -2231,7 +2216,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int j1, j2, j3, j4, j5; char affinity; int eType; - int r1, r2, r3; eType = sqlite3FindInIndex(pParse, pExpr, 0); @@ -2241,75 +2225,106 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ */ affinity = comparisonAffinity(pExpr); - if( target ){ - r1 = target; - }else{ - r1 = sqlite3GetTempReg(pParse); + if( target==0 ){ + target = inReg = ++pParse->nMem; } - inReg = r1; - sqlite3VdbeAddOp2(v, OP_Integer, 1, r1); + sqlite3VdbeAddOp2(v, OP_Integer, 1, target); /* Code the from " IN (...)". The temporary table ** pExpr->iTable contains the values that make up the (...) set. */ - r2 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r2); - sqlite3VdbeAddOp2(v, OP_Null, 0, r1); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); + sqlite3VdbeAddOp2(v, OP_Null, 0, target); j2 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j1); if( eType==IN_INDEX_ROWID ){ - j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r2, 0, 1); - j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r2); + j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1); + j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1); j5 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j3); sqlite3VdbeJumpHere(v, j4); }else{ - r3 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_RegMakeRec, r2, 1, r3, &affinity, 1); - j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r3); - sqlite3ReleaseTempReg(pParse, r3); + r2 = regFree2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1); + j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2); } - sqlite3VdbeAddOp2(v, OP_AddImm, r1, -1); + sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j5); break; } #endif + /* + ** x BETWEEN y AND z + ** + ** This is equivalent to + ** + ** x>=y AND x<=z + ** + ** X is stored in pExpr->pLeft. + ** Y is stored in pExpr->pList->a[0].pExpr. + ** Z is stored in pExpr->pList->a[1].pExpr. + */ case TK_BETWEEN: { Expr *pLeft = pExpr->pLeft; struct ExprList_item *pLItem = pExpr->pList->a; Expr *pRight = pLItem->pExpr; - int r1, r2, r3, r4, r5; - if( target>0 ){ - inReg = target; - }else{ - inReg = ++pParse->nMem; + if( target==0 ){ + inReg = target = ++pParse->nMem; } - r1 = sqlite3ExprCode(pParse, pLeft, -1); - r2 = sqlite3ExprCode(pParse, pRight, -1); - r3 = ++pParse->nMem; + r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); + r3 = sqlite3GetTempReg(pParse); codeCompare(pParse, pLeft, pRight, OP_Ge, r1, r2, r3, SQLITE_STOREP2); pLItem++; pRight = pLItem->pExpr; - r4 = sqlite3ExprCode(pParse, pRight, -1); - r5 = ++pParse->nMem; - codeCompare(pParse, pLeft, pRight, OP_Le, r1, r4, r5, SQLITE_STOREP2); - sqlite3VdbeAddOp3(v, OP_And, r3, r5, inReg); + sqlite3ReleaseTempReg(pParse, regFree2); + r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); + codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r2, SQLITE_STOREP2); + sqlite3VdbeAddOp3(v, OP_And, r3, r2, target); + sqlite3ReleaseTempReg(pParse, r3); break; } case TK_UPLUS: { - inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } + + /* + ** Form A: + ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END + ** + ** Form B: + ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END + ** + ** Form A is can be transformed into the equivalent form B as follows: + ** CASE WHEN x=e1 THEN r1 WHEN x=e2 THEN r2 ... + ** WHEN x=eN THEN rN ELSE y END + ** + ** X (if it exists) is in pExpr->pLeft. + ** Y is in pExpr->pRight. The Y is also optional. If there is no + ** ELSE clause and no other term matches, then the result of the + ** exprssion is NULL. + ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. + ** + ** The result of the expression is the Ri for the first matching Ei, + ** or if there is no matching Ei, the ELSE term Y, or if there is + ** no ELSE term, NULL. + */ case TK_CASE: { - int expr_end_label; - int jumpInst; - int nExpr; - int i; - ExprList *pEList; - struct ExprList_item *aListelem; + int endLabel; /* GOTO label for end of CASE stmt */ + int nextCase; /* GOTO label for next WHEN clause */ + int nExpr; /* 2x number of WHEN terms */ + int i; /* Loop counter */ + ExprList *pEList; /* List of WHEN terms */ + struct ExprList_item *aListelem; /* Array of WHEN terms */ + Expr opCompare; /* The X==Ei expression */ + Expr cacheX; /* Cached expression X */ + Expr *pX; /* The X expression */ + Expr *pTest; /* X==Ei (form A) or just Ei (form B) */ assert(pExpr->pList); assert((pExpr->pList->nExpr % 2) == 0); @@ -2317,34 +2332,33 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ pEList = pExpr->pList; aListelem = pEList->a; nExpr = pEList->nExpr; - expr_end_label = sqlite3VdbeMakeLabel(v); - if( pExpr->pLeft ){ - sqlite3ExprCode(pParse, pExpr->pLeft, 0); + endLabel = sqlite3VdbeMakeLabel(v); + if( (pX = pExpr->pLeft)!=0 ){ + cacheX = *pX; + cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, ®Free1); + cacheX.op = TK_REGISTER; + opCompare.op = TK_EQ; + opCompare.pLeft = &cacheX; + pTest = &opCompare; } for(i=0; ipLeft ){ - sqlite3VdbeAddOp1(v, OP_SCopy, -1); - jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr, - OP_Ne, 0, 0, 0, SQLITE_JUMPIFNULL); - sqlite3VdbeAddOp1(v, OP_Pop, 1); + if( pX ){ + opCompare.pRight = aListelem[i].pExpr; }else{ - jumpInst = sqlite3VdbeAddOp3(v, OP_IfNot, 0, 0, 1); + pTest = aListelem[i].pExpr; } + nextCase = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); - sqlite3VdbeAddOp2(v, OP_Goto, 0, expr_end_label); - sqlite3VdbeJumpHere(v, jumpInst); - } - if( pExpr->pLeft ){ - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel); + sqlite3VdbeResolveLabel(v, nextCase); } if( pExpr->pRight ){ sqlite3ExprCode(pParse, pExpr->pRight, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } - sqlite3VdbeResolveLabel(v, expr_end_label); - inReg = target; + sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -2371,44 +2385,78 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ } #endif } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); + return inReg; +} + +/* +** Generate code to evaluate an expression and store the results +** into a register. Return the register number where the results +** are stored. +** +** If the register is a temporary register that can be deallocated, +** then write its number into *pReg. If the result register is no +** a temporary, then set *pReg to zero. +*/ +int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ + int r1 = sqlite3GetTempReg(pParse); + int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); + if( r2==r1 ){ + *pReg = r1; + }else{ + sqlite3ReleaseTempReg(pParse, r1); + *pReg = 0; + } + return r2; +} + +/* +** Generate code that will evaluate expression pExpr and store the +** results in register target. The results are guaranteed to appear +** in register target. +*/ +int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ + int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ - if( origTarget!=-1 ){ - sqlite3VdbeAddOp2(v, (inReg>0 ? OP_SCopy : OP_Move), inReg, target); - }else{ - target = inReg; - } + sqlite3VdbeAddOp2(pParse->pVdbe, (inReg>0 ? OP_SCopy : OP_Move), + inReg, target); } return target; } -#ifndef SQLITE_OMIT_TRIGGER /* -** Generate code that evalutes the given expression and leaves the result -** on the stack. See also sqlite3ExprCode(). +** Generate code that evalutes the given expression and puts the result +** in register target. If target==-1, then allocate a temporary register +** in which to store the result. In either case, return the register +** number where the result is stored. +** +** Also make a copy of the expression results into another "cache" register +** and modify the expression so that the next time it is evaluated, +** the result is a copy of the cache register. ** -** This routine might also cache the result and modify the pExpr tree -** so that it will make use of the cached result on subsequent evaluations -** rather than evaluate the whole expression again. Trivial expressions are -** not cached. If the expression is cached, its result is stored in a -** memory location. +** This routine is used for expressions that are used multiple +** times. They are evaluated once and the results of the expression +** are reused. */ -void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ +int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; - VdbeOp *pOp; - int iMem; - int addr1, addr2; - if( v==0 ) return; - addr1 = sqlite3VdbeCurrentAddr(v); - sqlite3ExprCode(pParse, pExpr, target); - addr2 = sqlite3VdbeCurrentAddr(v); - if( addr2>addr1+1 - || ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){ - iMem = pExpr->iTable = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); + int inReg; + inReg = sqlite3ExprCode(pParse, pExpr, target); + if( pExpr->op!=TK_REGISTER ){ + int iMem; + if( target<0 ){ + iMem = inReg; + }else{ + iMem = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); + } + pExpr->iTable = iMem; pExpr->op = TK_REGISTER; } + return inReg; } -#endif + /* ** Generate code that pushes the value of every element of the given @@ -2457,6 +2505,10 @@ int sqlite3ExprCodeExprList( void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; + int regFree1 = 0; + int regFree2 = 0; + int r1, r2; + assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( v==0 || pExpr==0 ) return; op = pExpr->op; @@ -2489,51 +2541,58 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ assert( TK_GE==OP_Ge ); assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3ExprCode(pParse, pExpr->pRight, 0); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - 0, 0, dest, jumpIfNull); + r1, r2, dest, jumpIfNull); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3VdbeAddOp2(v, op, 0, dest); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + sqlite3VdbeAddOp2(v, op, r1, dest); break; } case TK_BETWEEN: { - /* The expression "x BETWEEN y AND z" is implemented as: + /* x BETWEEN y AND z + ** + ** Is equivalent to + ** + ** x>=y AND x<=z ** - ** 1 IF (x < y) GOTO 3 - ** 2 IF (x <= z) GOTO - ** 3 ... + ** Code it as such, taking care to do the common subexpression + ** elementation of x. */ - int addr; - Expr *pLeft = pExpr->pLeft; - Expr *pRight = pExpr->pList->a[0].pExpr; - sqlite3ExprCode(pParse, pLeft, 0); - sqlite3VdbeAddOp0(v, OP_Copy); - sqlite3ExprCode(pParse, pRight, 0); - addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, 0, 0, - jumpIfNull ^ SQLITE_JUMPIFNULL); - - pRight = pExpr->pList->a[1].pExpr; - sqlite3ExprCode(pParse, pRight, 0); - codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0, dest, jumpIfNull); - - sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); - sqlite3VdbeJumpHere(v, addr); - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); + Expr exprAnd; + Expr compLeft; + Expr compRight; + Expr exprX; + + exprX = *pExpr->pLeft; + exprAnd.op = TK_AND; + exprAnd.pLeft = &compLeft; + exprAnd.pRight = &compRight; + compLeft.op = TK_GE; + compLeft.pLeft = &exprX; + compLeft.pRight = pExpr->pList->a[0].pExpr; + compRight.op = TK_LE; + compRight.pLeft = &exprX; + compRight.pRight = pExpr->pList->a[1].pExpr; + exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1); + exprX.op = TK_REGISTER; + sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); break; } default: { - sqlite3ExprCode(pParse, pExpr, 0); - sqlite3VdbeAddOp3(v, OP_If, 0, dest, jumpIfNull!=0); + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); + sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); break; } } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); } /* @@ -2548,6 +2607,10 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; + int regFree1 = 0; + int regFree2 = 0; + int r1, r2; + assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( v==0 || pExpr==0 ) return; @@ -2605,49 +2668,56 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_GE: case TK_NE: case TK_EQ: { - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3ExprCode(pParse, pExpr->pRight, 0); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - 0, 0, dest, jumpIfNull); + r1, r2, dest, jumpIfNull); break; } case TK_ISNULL: case TK_NOTNULL: { - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3VdbeAddOp2(v, op, 0, dest); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + sqlite3VdbeAddOp2(v, op, r1, dest); break; } case TK_BETWEEN: { - /* The expression is "x BETWEEN y AND z". It is implemented as: + /* x BETWEEN y AND z + ** + ** Is equivalent to ** - ** 1 IF (x >= y) GOTO 3 - ** 2 GOTO - ** 3 IF (x > z) GOTO + ** x>=y AND x<=z + ** + ** Code it as such, taking care to do the common subexpression + ** elementation of x. */ - int addr; - Expr *pLeft = pExpr->pLeft; - Expr *pRight = pExpr->pList->a[0].pExpr; - sqlite3ExprCode(pParse, pLeft, 0); - sqlite3VdbeAddOp0(v, OP_Copy); - sqlite3ExprCode(pParse, pRight, 0); - addr = sqlite3VdbeCurrentAddr(v); - codeCompare(pParse, pLeft, pRight, OP_Ge, - 0, 0, addr+3, jumpIfNull ^ SQLITE_JUMPIFNULL); - - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); - pRight = pExpr->pList->a[1].pExpr; - sqlite3ExprCode(pParse, pRight, 0); - codeCompare(pParse, pLeft, pRight, OP_Gt, - 0, 0, dest, jumpIfNull); + Expr exprAnd; + Expr compLeft; + Expr compRight; + Expr exprX; + + exprX = *pExpr->pLeft; + exprAnd.op = TK_AND; + exprAnd.pLeft = &compLeft; + exprAnd.pRight = &compRight; + compLeft.op = TK_GE; + compLeft.pLeft = &exprX; + compLeft.pRight = pExpr->pList->a[0].pExpr; + compRight.op = TK_LE; + compRight.pLeft = &exprX; + compRight.pRight = pExpr->pList->a[1].pExpr; + exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1); + exprX.op = TK_REGISTER; + sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull); break; } default: { - sqlite3ExprCode(pParse, pExpr, 0); - sqlite3VdbeAddOp3(v, OP_IfNot, 0, dest, jumpIfNull!=0); + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); + sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); break; } } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); } /* @@ -2912,7 +2982,8 @@ int sqlite3GetTempReg(Parse *pParse){ } } void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ - if( pParse->nTempRegaTempReg)/sizeof(pParse->aTempReg[0]) ){ + if( iReg && pParse->nTempRegaTempReg) ){ + assert( iReg>0 ); pParse->aTempReg[pParse->nTempReg++] = iReg; } } diff --git a/src/select.c b/src/select.c index 6d28f40636..0ae6af2f07 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.398 2008/01/12 12:48:08 drh Exp $ +** $Id: select.c,v 1.399 2008/01/12 19:03:49 drh Exp $ */ #include "sqliteInt.h" @@ -455,18 +455,21 @@ static void codeOffset( ** stack if the top N elements are not distinct. */ static void codeDistinct( - Vdbe *v, /* Generate code into this VM */ + Parse *pParse, /* Parsing and code generating context */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ int N, /* Number of elements */ int iMem /* First element */ ){ - sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, N); - sqlite3VdbeAddOp2(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRepeat); - VdbeComment((v, "skip indistinct records")); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, 0); + Vdbe *v; + int r1; + + v = pParse->pVdbe; + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, N, r1); + sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1); + sqlite3ReleaseTempReg(pParse, r1); } /* @@ -564,7 +567,7 @@ static int selectInnerLoop( if( hasDistinct ){ assert( pEList!=0 ); assert( pEList->nExpr==nColumn ); - codeDistinct(v, distinct, iContinue, nColumn, iMem); + codeDistinct(pParse, distinct, iContinue, nColumn, iMem); if( pOrderBy==0 ){ codeOffset(v, p, iContinue); } @@ -2859,7 +2862,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( pF->iDistinct>=0 ){ addrNext = sqlite3VdbeMakeLabel(v); assert( nArg==1 ); - codeDistinct(v, pF->iDistinct, addrNext, 1, regAgg); + codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); } if( pF->pFunc->needCollSeq ){ CollSeq *pColl = 0; @@ -3440,22 +3443,17 @@ int sqlite3Select( addrTopOfLoop = sqlite3VdbeCurrentAddr(v); for(j=0; jnExpr; j++){ if( groupBySort ){ - sqlite3VdbeAddOp2(v, OP_Column, sAggInfo.sortingIdx, j); + sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j); }else{ sAggInfo.directMode = 1; - sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, 0); + sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } - sqlite3VdbeAddOp2(v, jnExpr-1?OP_Move:OP_Copy, 0, iBMem+j); } for(j=pGroupBy->nExpr-1; j>=0; j--){ - if( jnExpr-1 ){ - sqlite3VdbeAddOp2(v, OP_SCopy, iBMem+j, 0); - } - sqlite3VdbeAddOp2(v, OP_SCopy, iAMem+j, 0); if( j==0 ){ - sqlite3VdbeAddOp2(v, OP_Eq, 0, addrProcessRow); + sqlite3VdbeAddOp3(v, OP_Eq, iAMem+j, addrProcessRow, iBMem+j); }else{ - sqlite3VdbeAddOp2(v, OP_Ne, 0, addrGroupByChange); + sqlite3VdbeAddOp3(v, OP_Ne, iAMem+j, addrGroupByChange, iBMem+j); } sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQUAL); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d9c9dd40a6..83640d8424 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.648 2008/01/12 12:48:08 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.649 2008/01/12 19:03:49 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1400,6 +1400,7 @@ struct Parse { u8 nested; /* Number of nested calls to the parser/code generator */ u8 parseError; /* True after a parsing error. Ticket #1794 */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ + u8 nTempInUse; /* Number of aTempReg[] currently checked out */ int aTempReg[8]; /* Holding area for temporary registers */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ @@ -1768,7 +1769,8 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int); int sqlite3ExprCode(Parse*, Expr*, int); -void sqlite3ExprCodeAndCache(Parse*, Expr*, int); +int sqlite3ExprCodeTemp(Parse*, Expr*, int*); +int sqlite3ExprCodeAndCache(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); diff --git a/src/vdbe.c b/src/vdbe.c index b56babc3ac..d9936dbccd 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.693 2008/01/12 12:48:08 drh Exp $ +** $Id: vdbe.c,v 1.694 2008/01/12 19:03:49 drh Exp $ */ #include "sqliteInt.h" #include @@ -1062,17 +1062,6 @@ case OP_Variable: { /* out2-prerelease */ break; } -/* Opcode: Pop P1 * * * * -** -** P1 elements are popped off of the top of stack and discarded. -*/ -case OP_Pop: { /* no-push */ - assert( pOp->p1>=0 ); - popStack(&pTos, pOp->p1); - assert( pTos>=&p->aStack[-1] ); - break; -} - /* Opcode: Move P1 P2 * * * ** ** Move the value in P1 into P2. If P1 is positive then read from the @@ -1404,6 +1393,7 @@ case OP_Function: { for(i=0; ip2, pArg); } assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); @@ -1472,6 +1462,7 @@ case OP_Function: { if( sqlite3VdbeMemTooBig(pOut) ){ goto too_big; } + REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -3149,44 +3140,26 @@ case OP_MoveGt: { /* no-push, jump, in3 */ break; } -/* Opcode: Distinct P1 P2 P3 * * -** -** Use register P3 as a record created using MakeRecord. P1 is a -** cursor on a table that declared as an index. If that table contains an -** entry that matches the top of the stack fall thru. If the top of the stack -** matches no entry in P1 then jump to P2. -** -** The cursor is left pointing at the matching entry if it exists. The -** record on the top of the stack is not popped. -** -** This instruction is similar to NotFound except that this operation -** does not pop the key from the stack when P3==0. -** -** The instruction is used to implement the DISTINCT operator on SELECT -** statements. The P1 table is not a true index but rather a record of -** all results that have produced so far. -** -** See also: Found, NotFound, MoveTo, IsUnique, NotExists -*/ /* Opcode: Found P1 P2 P3 * * ** ** Register P3 holds a blob constructed by MakeRecord. P1 is an index. ** If an entry that matches the top of the stack exists in P1 then ** jump to P2. If the top of the stack does not match any entry in P1 ** then fall thru. The P1 cursor is left pointing at the matching entry -** if it exists. The blob is popped off the top of the stack. +** if it exists. ** ** This instruction is used to implement the IN operator where the ** left-hand side is a SELECT statement. P1 may be a true index, or it ** may be a temporary index that holds the results of the SELECT -** statement. +** statement. This instruction is also used to implement the +** DISTINCT keyword in SELECT statements. ** ** This instruction checks if index P1 contains a record for which ** the first N serialised values exactly match the N serialised values ** in the record on the stack, where N is the total number of values in ** the stack record (stack record is a prefix of the P1 record). ** -** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists +** See also: NotFound, MoveTo, IsUnique, NotExists */ /* Opcode: NotFound P1 P2 P3 * * ** @@ -3200,7 +3173,6 @@ case OP_MoveGt: { /* no-push, jump, in3 */ ** ** See also: Distinct, Found, MoveTo, NotExists, IsUnique */ -case OP_Distinct: /* no-push, jump, in3 */ case OP_NotFound: /* no-push, jump, in3 */ case OP_Found: { /* no-push, jump, in3 */ int i = pOp->p1; @@ -3229,9 +3201,6 @@ case OP_Found: { /* no-push, jump, in3 */ }else{ if( !alreadyExists ) pc = pOp->p2 - 1; } - if( pOp->opcode==OP_Distinct ){ - nPop = 0; - } break; } diff --git a/src/where.c b/src/where.c index 0fd137ada0..90d2b87ddf 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.280 2008/01/09 23:04:13 drh Exp $ +** $Id: where.c,v 1.281 2008/01/12 19:03:49 drh Exp $ */ #include "sqliteInt.h" @@ -2591,8 +2591,7 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp1(v, OP_Copy, 1-nEq); } buildIndexProbe(v, nEq, pIdx); - sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem); - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem); sqlite3VdbeAddOp2(v, OP_Null, 0, 0); buildIndexProbe(v, nEq+1, pIdx); }else{ diff --git a/test/func.test b/test/func.test index 8ae7edd702..c2d7ead547 100644 --- a/test/func.test +++ b/test/func.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # -# $Id: func.test,v 1.71 2007/11/28 22:36:41 drh Exp $ +# $Id: func.test,v 1.72 2008/01/12 19:03:49 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -438,9 +438,9 @@ do_test func-12.2 { } {0} do_test func-12.3 { execsql { - SELECT test_destructor('hello')||' world', test_destructor_count(); + SELECT test_destructor('hello')||' world' } -} {{hello world} 0} +} {{hello world}} do_test func-12.4 { execsql { SELECT test_destructor_count();