From 1db639cef348d19d4b92d24825c4634b0a1589ea Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Jan 2008 02:36:28 +0000 Subject: [PATCH] Registerification of the WHERE clause logic. (CVS 4716) FossilOrigin-Name: b3a141b2b0c09bf3c7704deeade290d71b7c9b77 --- manifest | 44 +++++----- manifest.uuid | 2 +- src/analyze.c | 4 +- src/build.c | 22 +++-- src/delete.c | 22 +---- src/expr.c | 6 +- src/insert.c | 31 ++++--- src/pragma.c | 10 +-- src/select.c | 20 ++--- src/sqliteInt.h | 3 +- src/trigger.c | 12 +-- src/update.c | 4 +- src/vdbe.c | 93 +++------------------ src/vdbeaux.c | 10 ++- src/where.c | 203 ++++++++++++++++++++++++---------------------- test/tester.tcl | 4 +- test/vacuum.test | 24 +++--- test/vacuum2.test | 14 ++-- 18 files changed, 227 insertions(+), 301 deletions(-) diff --git a/manifest b/manifest index 7f563f0edb..4abd99c0af 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\s1<<$x\sinstead\sof\spow(2,$x)\sin\sthe\stest\ssuite\scode.\s(CVS\s4715) -D 2008-01-16T18:20:42 +C Registerification\sof\sthe\sWHERE\sclause\slogic.\s(CVS\s4716) +D 2008-01-17T02:36:28 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -79,24 +79,24 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04 -F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1 +F src/analyze.c ac17da1f9c804aabf709a1afff12ed35fc215104 F src/attach.c 71f5c886004a9740fc6e6033d4e1ce0517ab6574 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76 -F src/build.c c0f9dba7028d415fb8d282e34a8ebcf69614befd +F src/build.c ea291f091434aa9cd9700ea1611f2601c3c6a118 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 -F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9 +F src/delete.c ca07deed95f6f79c64338147147f698811628dc9 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c be1018f2911bd93e6fc34f216ed263ce733569b6 +F src/expr.c 00ee6555e323cd772f85e48b353109865d1eb539 F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c a19d9f51b611943386fcff714e3a0ffb137e463b +F src/insert.c 8a90ba2d934bef98562cee12b778a17446730594 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 @@ -127,16 +127,16 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 0cb6ccea4b9615627d61d7c4417cedc45776d429 F src/pager.h f504f7ae84060fee0416a853e368d3d113c3d6fa F src/parse.y 2ae06e8d3190faace49c5b82e7cea1fc60d084a1 -F src/pragma.c b4e77e057990bb2c295c63327406d9bcbf6c9c08 +F src/pragma.c 0768de04ea4e97c8c79748110147c5bc6986c440 F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 02ef38b469237482f1ea14a78b2087cfbaec48bd -F src/select.c 578f7b01047b20349ead5a36d7e64274a61bea80 +F src/select.c 841eba5f83fb81f267bb2633bbf1b0cb7cfda96f F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 0691a3d52dc37cf6ac2f74838e5ff8ae1055ac9b F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h c3f43826e48b0d2928b9e6fa3aca887317285392 +F src/sqliteInt.h 89dc8eb7784948ef80966addc645721e20f9b772 F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf @@ -163,21 +163,21 @@ F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5 F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48 -F src/trigger.c 3a863b9952164ab5de58406c26daf06144bbddc4 -F src/update.c aad823f97a930e6982264299863837d4c6107d3b +F src/trigger.c 5e869352a2f35890dc4711161bfe958fcec8f4d7 +F src/update.c a4da9976e06bf1cc676dc270e0e0dba8ae39729c F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c 1c58599437d048a2d14c5ce04e4576d2e3e78dfc +F src/vdbe.c 9de1ce4ddf2906a63cef6bd11156d299edf31cd0 F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346 F src/vdbeapi.c cb8c427a3ab646490c83204a98e94eff03ee2e89 -F src/vdbeaux.c 1bf7dbab24af0be35855abd5e4d9c6290e38f4ce +F src/vdbeaux.c e5b401253f66f099c5d790dcbee43d614681eae5 F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c -F src/where.c 27e40d32b7b47e70db9ac61b91a3a46c8dc6b47d +F src/where.c 75908cb6dbcc7f2f21e42d65b68b1a24e6b5f679 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test ee350b9ab15b175fc0a8fb51bf2141ed3a3b9cba @@ -445,7 +445,7 @@ F test/table.test 13b1c2e2fb4727b35ee1fb7641fc469214fd2455 F test/tableapi.test 92651a95c23cf955e92407928e640536402fa3cc F test/tclsqlite.test 3fac87cb1059c46b8fa8a60b553f4f1adb0fb6d9 F test/temptable.test 19b851b9e3e64d91e9867619b2a3f5fffee6e125 -F test/tester.tcl f851528e033e40b2c708eebf09c6ab4cb27c47d4 +F test/tester.tcl 493be4c2f8f4ea561d91c448b37da2d30fedb3f9 F test/thread001.test 8fbd9559da0bbdc273e00318c7fd66c162020af7 F test/thread002.test 2c4ad2c386f60f6fe268cd91c769ee35b3c1fd0b F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 @@ -504,8 +504,8 @@ F test/unique.test 0253c4227a5dc533e312202ce21ecfad18058d18 F test/update.test 24c1dcc025f7ef352759afe3f4a20e6fdfd43a97 F test/utf16.test 20e2d9ba0d57e952a18b1ac8deab9ad49e082893 F test/utf16align.test 7360e84472095518c56746f76b1f9d4dce99fb4d -F test/vacuum.test 7493b09398d576b69a8b2f55bac92d50a9b8e796 -F test/vacuum2.test 970acadc2b4c3342fa2584410d96eae2c2b37c25 +F test/vacuum.test f67853a15caa120af591f819670f01a11fcc2bfc +F test/vacuum2.test d3b9691541fe6ed5c711f547a1c7d70e9760ac6f F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/view.test 7e15fa1ba3267ddaa9ae96b6daf519f23f95b43e F test/vtab1.test bd905d1d43637a700308da6ffcc4e014c27e2f0a @@ -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 5807921f5a6e2e08f2c9e79aa91d8c587d64de74 -R 871f72c6ea2165bc803ac14747ee932f -U danielk1977 -Z b5d54334b931393ae4ef6244d18f48c7 +P 3a289b6d28bcf399845586b15f100d7c3a78b550 +R 9b81ffae960f644182cd49ff81018f5f +U drh +Z ae8f3f9d0f33bb8446db7603cd67f9f8 diff --git a/manifest.uuid b/manifest.uuid index 9b37b9fa11..21515d6ecf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3a289b6d28bcf399845586b15f100d7c3a78b550 \ No newline at end of file +b3a141b2b0c09bf3c7704deeade290d71b7c9b77 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index a1bc2ee3c0..b7e917fb67 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.38 2008/01/12 12:48:08 drh Exp $ +** @(#) $Id: analyze.c,v 1.39 2008/01/17 02:36:28 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -216,7 +216,7 @@ static void analyzeOneTable( sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2); } - sqlite3VdbeAddOp4(v, OP_RegMakeRec, regFields, 3, regRec, "aaa", 0); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regFields, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); diff --git a/src/build.c b/src/build.c index 26ae87d221..91d94f04ef 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.465 2008/01/12 21:35:57 drh Exp $ +** $Id: build.c,v 1.466 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include @@ -2215,7 +2215,7 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ ** content of an index in response to a REINDEX command. ** ** if memRootPage is not negative, it means that the index is newly -** created. The memory cell specified by memRootPage contains the +** created. The register specified by memRootPage contains the ** root page number of the index. If memRootPage is negative, then ** the index already exists and must be cleared before being refilled and ** the root page number of the index is taken from pIndex->tnum. @@ -2246,8 +2246,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ - sqlite3VdbeAddOp1(v, OP_SCopy, memRootPage); - tnum = 0; + tnum = memRootPage; }else{ tnum = pIndex->tnum; sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); @@ -2736,12 +2735,17 @@ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ Vdbe *v; v = sqlite3GetVdbe(pParse); if( v ){ - sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 0, 1); + int r1 = sqlite3GetTempReg(pParse); + int r2 = sqlite3GetTempReg(pParse); + int j1; + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, 1); sqlite3VdbeUsesBtree(v, iDb); - sqlite3VdbeAddOp1(v, OP_Integer, minFormat); - sqlite3VdbeAddOp2(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp1(v, OP_Integer, minFormat); - sqlite3VdbeAddOp2(v, OP_SetCookie, iDb, 1); + sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2); + j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, r2); + sqlite3VdbeJumpHere(v, j1); + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempReg(pParse, r2); } } diff --git a/src/delete.c b/src/delete.c index 87436ae935..ae2ecf9115 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.157 2008/01/12 12:48:08 drh Exp $ +** $Id: delete.c,v 1.158 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" @@ -60,24 +60,6 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ return 0; } -/* -** Allocate nVal contiguous memory cells and return the index of the -** first. Also pop nVal elements from the stack and store them in the -** registers. The element on the top of the stack is stored in the -** register with the largest index. -*/ -int sqlite3StackToReg(Parse *p, int nVal){ - int i; - int iRet = p->nMem+1; - Vdbe *v = sqlite3GetVdbe(p); - assert(v); - p->nMem += nVal; - for(i=nVal-1; i>=0; i--){ - sqlite3VdbeAddOp2(v, OP_Move, 0, iRet+i); - } - return iRet; -} - /* ** Generate code that will open a table for reading. */ @@ -519,7 +501,7 @@ int sqlite3GenerateIndexKey( sqlite3ColumnDefault(v, pTab, idx); } } - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nCol+1, regOut); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); sqlite3IndexAffinityStr(v, pIdx); sqlite3ReleaseTempRange(pParse, regBase, nCol+1); return regBase; diff --git a/src/expr.c b/src/expr.c index 52a0f29def..559939826c 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.345 2008/01/13 19:02:11 drh Exp $ +** $Id: expr.c,v 1.346 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include @@ -1786,7 +1786,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2, r1); - sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } sqlite3ReleaseTempReg(pParse, r1); @@ -2246,7 +2246,7 @@ static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3VdbeJumpHere(v, j4); }else{ r2 = regFree2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2); } sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); diff --git a/src/insert.c b/src/insert.c index 024a3403f4..158dbae4d4 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.223 2008/01/12 12:48:08 drh Exp $ +** $Id: insert.c,v 1.224 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" @@ -174,15 +174,15 @@ static int autoIncBegin( pParse->nMem++; sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); addr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+8); - sqlite3VdbeAddOp2(v, OP_Column, iCur, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); - sqlite3VdbeAddOp2(v, OP_Ne, 0, addr+7); + sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId); + sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1); sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+8); - sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); + sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2); sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); } return memId; @@ -224,8 +224,7 @@ static void autoIncEnd( j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, memId-1, 2, memId-1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, memId-1); sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp1(v, OP_Close, iCur); @@ -525,7 +524,7 @@ void sqlite3Insert( regRec = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeResolveLabel(v, iInsertBlock); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regFromSelect, nColumn, regRec); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); @@ -738,7 +737,7 @@ void sqlite3Insert( } } regRec = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRec); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRec); /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. @@ -777,7 +776,7 @@ void sqlite3Insert( sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid); }else{ VdbeOp *pOp; - sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0); + sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid); pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); if( pOp && pOp->opcode==OP_Null ){ appendFlag = 1; @@ -785,18 +784,16 @@ void sqlite3Insert( pOp->p1 = baseCur; pOp->p2 = regRowid; pOp->p3 = regAutoinc; - }else{ - /* TODO: Avoid this use of the stack. */ - sqlite3VdbeAddOp2(v, OP_Move, 0, regRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if( !appendFlag ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, sqlite3VdbeCurrentAddr(v)+2); - sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2); + int j1; + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); + sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } }else if( IsVirtual(pTab) ){ @@ -1178,7 +1175,7 @@ void sqlite3GenerateConstraintChecks( } } sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); @@ -1294,7 +1291,7 @@ void sqlite3CompleteInsertion( } regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regData, pTab->nCol, regRec); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ diff --git a/src/pragma.c b/src/pragma.c index e362f76179..11350aea9e 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.166 2008/01/12 21:35:57 drh Exp $ +** $Id: pragma.c,v 1.167 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include @@ -459,11 +459,11 @@ void sqlite3Pragma( */ static const VdbeOpList setMeta6[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ - { OP_ReadCookie, 0, 0, 3}, /* 1 */ - { OP_If, 0, 0, 0}, /* 2 */ + { OP_ReadCookie, 0, 1, 3}, /* 1 */ + { OP_If, 1, 0, 0}, /* 2 */ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ - { OP_Integer, 0, 0, 0}, /* 4 */ - { OP_SetCookie, 0, 6, 0}, /* 5 */ + { OP_Integer, 0, 1, 0}, /* 4 */ + { OP_SetCookie, 0, 6, 1}, /* 5 */ }; int iAddr; iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6); diff --git a/src/select.c b/src/select.c index 7538494021..3f181d4f7d 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.402 2008/01/15 02:22:24 drh Exp $ +** $Id: select.c,v 1.403 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" @@ -404,7 +404,7 @@ static void pushOntoSorter( sqlite3ExprCodeExprList(pParse, pOrderBy, regBase); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nExpr + 2, regRecord); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); @@ -466,7 +466,7 @@ static void codeDistinct( v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, N, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1); sqlite3ReleaseTempReg(pParse, r1); @@ -583,7 +583,7 @@ static int selectInnerLoop( */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { - sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); + sqlite3VdbeAddOp2(v, OP_MakeRecord, iMem, nColumn); if( aff ){ sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); } @@ -597,7 +597,7 @@ static int selectInnerLoop( */ case SRT_Except: { int addr; - addr = sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); + addr = sqlite3VdbeAddOp2(v, OP_MakeRecord, iMem, nColumn); sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); sqlite3VdbeAddOp2(v, OP_NotFound, iParm, addr+3); sqlite3VdbeAddOp2(v, OP_Delete, iParm, 0); @@ -610,7 +610,7 @@ static int selectInnerLoop( case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, nColumn, r1); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p, r1); }else{ @@ -643,7 +643,7 @@ static int selectInnerLoop( pushOntoSorter(pParse, pOrderBy, p, iMem); }else{ int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, r1, &p->affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, iMem, 1, r1, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); } @@ -683,7 +683,7 @@ static int selectInnerLoop( case SRT_Callback: { if( pOrderBy ){ int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, nColumn, r1); pushOntoSorter(pParse, pOrderBy, p, r1); sqlite3ReleaseTempReg(pParse, r1); }else if( eDest==SRT_Subroutine ){ @@ -808,7 +808,7 @@ static void generateSortTail( int j1; assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); - sqlite3VdbeAddOp4(v, OP_RegMakeRec, regRow, 1, regRow, &p->affinity, 1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRow, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); sqlite3VdbeJumpHere(v, j1); break; @@ -3430,7 +3430,7 @@ int sqlite3Select( } } regRecord = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nCol, regRecord); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, sAggInfo.sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 83640d8424..12552e404f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.649 2008/01/12 19:03:49 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.650 2008/01/17 02:36:28 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1949,7 +1949,6 @@ int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); -int sqlite3StackToReg(Parse *, int); void sqlite3SelectDestInit(SelectDest*,int,int); /* diff --git a/src/trigger.c b/src/trigger.c index 310d60f1ba..09cbc437ce 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -523,12 +523,12 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ int base; static const VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, - { OP_String8, 0, 0, 0}, /* 1 */ - { OP_Column, 0, 1, 0}, - { OP_Ne, 0, ADDR(8), 0}, - { OP_String8, 0, 0, 0}, /* 4: "trigger" */ - { OP_Column, 0, 0, 0}, - { OP_Ne, 0, ADDR(8), 0}, + { OP_String8, 0, 1, 0}, /* 1 */ + { OP_Column, 0, 1, 2}, + { OP_Ne, 2, ADDR(8), 1}, + { OP_String8, 0, 1, 0}, /* 4: "trigger" */ + { OP_Column, 0, 0, 2}, + { OP_Ne, 2, ADDR(8), 1}, { OP_Delete, 0, 0, 0}, { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; diff --git a/src/update.c b/src/update.c index 6d1a21f414..8d39dbc758 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.167 2008/01/10 23:50:11 drh Exp $ +** $Id: update.c,v 1.168 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" @@ -449,7 +449,7 @@ void sqlite3Update( sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i); } } - sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRow); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRow); if( !isView ){ sqlite3TableAffinityStr(v, pTab); } diff --git a/src/vdbe.c b/src/vdbe.c index bd4e3bf85c..144aafc18b 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.696 2008/01/16 17:46:38 drh Exp $ +** $Id: vdbe.c,v 1.697 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include @@ -1984,27 +1984,6 @@ case OP_IfNot: { /* no-push, jump, in1 */ break; } -/* Opcode: StackIsNull P1 P2 * -** -** Check the top of the stack and jump to P2 if the top of the stack -** is NULL. If P1 is positive, then pop P1 elements from the stack -** regardless of whether or not the jump is taken. If P1 is negative, -** pop -P1 elements from the stack only if the jump is taken and leave -** the stack unchanged if the jump is not taken. -*/ -case OP_StackIsNull: { /* no-push, jump */ - if( pTos->flags & MEM_Null ){ - pc = pOp->p2-1; - if( pOp->p1<0 ){ - popStack(&pTos, -pOp->p1); - } - } - if( pOp->p1>0 ){ - popStack(&pTos, pOp->p1); - } - break; -} - /* Opcode: IsNull P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is NULL. If P3 is greater @@ -2319,9 +2298,9 @@ op_column_out: break; } -/* Opcode: MakeRecord P1 P2 P4 +/* Opcode: MakeRecord P1 P2 P3 P4 * ** -** Convert the top abs(P1) entries of the stack into a single entry +** Convert P2 registers beginning with P1 into a single entry ** suitable for use as a data record in a database table or as a key ** in an index. The details of the format are irrelavant as long as ** the OP_Column opcode can decode the record later and as long as the @@ -2329,13 +2308,6 @@ op_column_out: ** records. Refer to source code comments for the details of the record ** format. ** -** The original stack entries are popped from the stack if P1>0 but -** remain on the stack if P1<0. -** -** If P2 is not zero and one or more of the entries are NULL, then jump -** to the address given by P2. This feature can be used to skip a -** uniqueness test on indices. -** ** P4 may be a string that is P1 characters long. The nth character of the ** string indicates the column affinity that should be used for the nth ** field of the index key (i.e. the first character of P4 corresponds to the @@ -2346,17 +2318,7 @@ op_column_out: ** ** If P4 is NULL then all index fields have the affinity NONE. */ -/* -** Opcode: RegMakeRec P1 P2 P3 P4 * -** -** Builds a record like OP_MakeRecord. But the data is taken from -** P2 registers beginning with P1: P1, P1+1, P1+2, ..., P1+P2-1. -** The result is written into P3 or pushed onto the stack if P3 is zero. -** There is no jump on NULL - that can be done with a separate -** OP_AnyNull opcode. -*/ -case OP_RegMakeRec: -case OP_MakeRecord: { /* jump */ +case OP_MakeRecord: { /* Assuming the record contains N fields, the record format looks ** like this: ** @@ -2380,41 +2342,20 @@ case OP_MakeRecord: { /* jump */ int nZero = 0; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ - int containsNull = 0; /* True if any of the data fields are NULL */ - Mem *pData0; /* Bottom of the stack */ - Mem *pLast; /* Top of the stack */ - int leaveOnStack; /* If true, leave the entries on the stack */ + Mem *pData0; /* First field to be combined into the record */ + Mem *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ - int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ char zTemp[NBFS]; /* Space to hold small records */ - if( pOp->p1<0 ){ - assert( pOp->opcode==OP_MakeRecord ); - leaveOnStack = 1; - nField = -pOp->p1; - }else{ - leaveOnStack = 0; - nField = pOp->p1; - } + nField = pOp->p1; zAffinity = pOp->p4.z; - - if( pOp->opcode==OP_RegMakeRec ){ - assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); - pData0 = &p->aMem[nField]; - nField = pOp->p2; - leaveOnStack = 1; - jumpIfNull = 0; - pLast = &pData0[nField-1]; - }else{ - jumpIfNull = pOp->p2; - pData0 = &pTos[1-nField]; - pLast = pTos; - assert( pData0>=p->aStack ); - } - containsNull = 0; + assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); + pData0 = &p->aMem[nField]; + nField = pOp->p2; + pLast = &pData0[nField-1]; file_format = p->minWriteFileFormat; /* Loop through the elements that will make up the record to figure @@ -2425,9 +2366,6 @@ case OP_MakeRecord: { /* jump */ if( zAffinity ){ applyAffinity(pRec, zAffinity[pRec-pData0], encoding); } - if( pRec->flags&MEM_Null ){ - containsNull = 1; - } if( pRec->flags&MEM_Zero && pRec->n>0 ){ ExpandBlob(pRec); } @@ -2475,10 +2413,6 @@ case OP_MakeRecord: { /* jump */ } assert( i==nByte ); - /* Pop entries off the stack if required. Push the new record on. */ - if( !leaveOnStack ){ - popStack(&pTos, nField); - } if( pOp->p3==0 ){ pOut = ++pTos; }else{ @@ -2504,11 +2438,6 @@ case OP_MakeRecord: { /* jump */ pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); - - /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ - if( jumpIfNull && containsNull ){ - pc = jumpIfNull - 1; - } break; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9d1592fdda..95d4818843 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -717,11 +717,17 @@ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP4; char zPtr[50]; - static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X\n"; + static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n"; if( pOut==0 ) pOut = stdout; zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); fprintf(pOut, zFormat1, pc, - sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5); + sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5, +#ifdef SQLITE_DEBUG + pOp->zComment ? pOp->zComment : "" +#else + "" +#endif + ); fflush(pOut); } #endif diff --git a/src/where.c b/src/where.c index 90d2b87ddf..e046ba6eca 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.281 2008/01/12 19:03:49 drh Exp $ +** $Id: where.c,v 1.282 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" @@ -1705,9 +1705,13 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ static void buildIndexProbe( Vdbe *v, /* Generate code into this VM */ int nColumn, /* The number of columns to check for NULL */ - Index *pIdx /* Index that we will be searching */ + Index *pIdx, /* Index that we will be searching */ + int regSrc, /* Take values from this register */ + int regDest /* Write the result into this register */ ){ - sqlite3VdbeAddOp2(v, OP_MakeRecord, nColumn, 0); + assert( regSrc>0 ); + assert( regDest>0 ); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest); sqlite3IndexAffinityStr(v, pIdx); } @@ -1717,7 +1721,7 @@ static void buildIndexProbe( ** term can be either X=expr or X IN (...). pTerm is the term to be ** coded. ** -** The current value for the constraint is left on the top of the stack. +** The current value for the constraint is left in register iReg. ** ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) @@ -1726,14 +1730,17 @@ static void buildIndexProbe( static void codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ - WhereLevel *pLevel /* When level of the FROM clause we are working on */ + WhereLevel *pLevel, /* When level of the FROM clause we are working on */ + int iReg /* Leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; + + assert( iReg>0 && iReg<=pParse->nMem ); if( pX->op==TK_EQ ){ - sqlite3ExprCode(pParse, pX->pRight, 0); + sqlite3ExprCode(pParse, pX->pRight, iReg); }else if( pX->op==TK_ISNULL ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; @@ -1753,11 +1760,14 @@ static void codeEqualityTerm( sizeof(pLevel->aInLoop[0])*pLevel->nIn); pIn = pLevel->aInLoop; if( pIn ){ - int op = ((eType==IN_INDEX_ROWID)?OP_Rowid:OP_Column); pIn += pLevel->nIn - 1; pIn->iCur = iTab; - pIn->topAddr = sqlite3VdbeAddOp2(v, op, iTab, 0); - sqlite3VdbeAddOp2(v, OP_StackIsNull, -1, 0); + if( eType==IN_INDEX_ROWID ){ + pIn->topAddr = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); + }else{ + pIn->topAddr = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); + } + sqlite3VdbeAddOp1(v, OP_IsNull, iReg); }else{ pLevel->nIn = 0; } @@ -1789,30 +1799,29 @@ static void codeEqualityTerm( ** this routine allocates an additional nEq memory cells for internal ** use. */ -static void codeAllEqualityTerms( +static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ WhereClause *pWC, /* The WHERE clause */ - Bitmask notReady /* Which parts of FROM have not yet been coded */ + Bitmask notReady, /* Which parts of FROM have not yet been coded */ + int nExtraReg /* Number of extra registers to allocate */ ){ int nEq = pLevel->nEq; /* The number of == or IN constraints to code */ - int termsInMem = 0; /* If true, store value in mem[] cells */ Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */ Index *pIdx = pLevel->pIdx; /* The index being used for this loop */ int iCur = pLevel->iTabCur; /* The cursor of the table */ WhereTerm *pTerm; /* A single constraint term */ int j; /* Loop counter */ + int regBase; /* Base register */ /* 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. */ - pLevel->iMem = ++pParse->nMem; - if( pLevel->flags & WHERE_COLUMN_IN ){ - pParse->nMem += pLevel->nEq; - termsInMem = 1; - } + pLevel->iMem = pParse->nMem + 1; + regBase = pParse->nMem + 2; + pParse->nMem += pLevel->nEq + 2 + nExtraReg; /* Evaluate the equality constraints */ @@ -1822,22 +1831,12 @@ static void codeAllEqualityTerms( pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx); if( pTerm==0 ) break; assert( (pTerm->flags & TERM_CODED)==0 ); - codeEqualityTerm(pParse, pTerm, pLevel); + codeEqualityTerm(pParse, pTerm, pLevel, regBase+j); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ - sqlite3VdbeAddOp2(v, OP_StackIsNull, termsInMem ? -1 : -(j+1), pLevel->brk); - } - if( termsInMem ){ - sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem+j+1); - } - } - - /* Make sure all the constraint values are on the top of the stack - */ - if( termsInMem ){ - for(j=0; jiMem+j+1, 0); + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk); } } + return regBase; } #if defined(SQLITE_TEST) @@ -2285,24 +2284,23 @@ WhereInfo *sqlite3WhereBegin( const struct sqlite3_index_constraint *aConstraint = pBestIdx->aConstraint; + iReg = sqlite3GetTempRange(pParse, nConstraint+2); for(j=1; j<=nConstraint; j++){ int k; for(k=0; kpRight, 0); + sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight, iReg+j+1); break; } } if( k==nConstraint ) break; } - iReg = ++pParse->nMem; - pParse->nMem++; - sqlite3StackToReg(pParse, j-1); sqlite3VdbeAddOp2(v, OP_Integer, pBestIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, brk, iReg, pBestIdx->idxStr, pBestIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); + sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); pBestIdx->needToFreeIdxStr = 0; for(j=0; jnConstraint; j++){ if( aUsage[j].omit ){ @@ -2322,16 +2320,19 @@ WhereInfo *sqlite3WhereBegin( ** we reference multiple rows using a "rowid IN (...)" ** construct. */ + int r1; pTerm = findTerm(&wc, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( pTerm->leftCursor==iCur ); assert( omitTable==0 ); - codeEqualityTerm(pParse, pTerm, pLevel); + r1 = sqlite3GetTempReg(pParse); + codeEqualityTerm(pParse, pTerm, pLevel, r1); nxt = pLevel->nxt; - sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, nxt, 1); - sqlite3VdbeAddOp2(v, OP_NotExists, iCur, nxt); + sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, nxt, 1); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, nxt, r1); VdbeComment((v, "pk")); + sqlite3ReleaseTempReg(pParse, r1); pLevel->op = OP_Noop; }else if( pLevel->flags & WHERE_ROWID_RANGE ){ /* Case 2: We have an inequality comparison against the ROWID field. @@ -2350,14 +2351,16 @@ WhereInfo *sqlite3WhereBegin( } if( pStart ){ Expr *pX; + int r1, regFree1; pX = pStart->pExpr; assert( pX!=0 ); assert( pStart->leftCursor==iCur ); - sqlite3ExprCode(pParse, pX->pRight, 0); - sqlite3VdbeAddOp3(v, OP_ForceInt, 0, brk, + r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, ®Free1); + sqlite3VdbeAddOp3(v, OP_ForceInt, r1, brk, pX->op==TK_LE || pX->op==TK_GT); - sqlite3VdbeAddOp2(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk); + sqlite3VdbeAddOp3(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk, r1); VdbeComment((v, "pk")); + sqlite3ReleaseTempReg(pParse, regFree1); disableTerm(pLevel, pStart); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, brk); @@ -2367,9 +2370,8 @@ WhereInfo *sqlite3WhereBegin( pX = pEnd->pExpr; assert( pX!=0 ); assert( pEnd->leftCursor==iCur ); - sqlite3ExprCode(pParse, pX->pRight, 0); pLevel->iMem = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem); + sqlite3ExprCode(pParse, pX->pRight, pLevel->iMem); if( pX->op==TK_LT || pX->op==TK_GT ){ testOp = bRev ? OP_Le : OP_Ge; }else{ @@ -2382,10 +2384,12 @@ WhereInfo *sqlite3WhereBegin( pLevel->p1 = iCur; pLevel->p2 = start; if( testOp!=OP_Noop ){ - sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); - sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); - sqlite3VdbeAddOp2(v, testOp, 0, brk); + 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 @@ -2408,19 +2412,13 @@ WhereInfo *sqlite3WhereBegin( 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 */ /* Generate code to evaluate all constraint terms using == or IN ** and level the values of those terms on the stack. */ - codeAllEqualityTerms(pParse, pLevel, &wc, notReady); - - /* Duplicate the equality term values because they will all be - ** used twice: once to make the termination key and once to make the - ** start key. - */ - for(j=0; j or >= @@ -2462,13 +2460,13 @@ WhereInfo *sqlite3WhereBegin( nxt = pLevel->nxt; if( topLimit ){ Expr *pX; - int k = pIdx->aiColumn[j]; + 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, 0); - sqlite3VdbeAddOp2(v, OP_StackIsNull, -(nEq*2+1), nxt); + 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; @@ -2478,18 +2476,15 @@ WhereInfo *sqlite3WhereBegin( } if( testOp!=OP_Noop || (isMinQuery&&bRev) ){ int nCol = nEq + topLimit; - pLevel->iMem = ++pParse->nMem; if( isMinQuery && !topLimit ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); nCol++; - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); topEq = 0; } - buildIndexProbe(v, nCol, pIdx); + buildIndexProbe(v, nCol, pIdx, regBase, pLevel->iMem); if( bRev ){ int op = topEq ? OP_MoveLe : OP_MoveLt; - sqlite3VdbeAddOp2(v, op, iIdxCur, nxt); - }else{ - sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem); + sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem); } }else if( bRev ){ sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk); @@ -2506,13 +2501,13 @@ WhereInfo *sqlite3WhereBegin( */ if( btmLimit ){ Expr *pX; - int k = pIdx->aiColumn[j]; + 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, 0); - sqlite3VdbeAddOp2(v, OP_StackIsNull, -(nEq+1), nxt); + sqlite3ExprCode(pParse, pX->pRight, regBase+nEq); + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); btmEq = pTerm->eOperator & (WO_LE|WO_GE); disableTerm(pLevel, pTerm); }else{ @@ -2521,18 +2516,21 @@ WhereInfo *sqlite3WhereBegin( if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){ int nCol = nEq + btmLimit; if( isMinQuery && !btmLimit ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); nCol++; - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); btmEq = 0; } - buildIndexProbe(v, nCol, pIdx); if( bRev ){ - pLevel->iMem = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem); + r1 = pLevel->iMem; testOp = OP_IdxLT; }else{ + r1 = sqlite3GetTempReg(pParse); + } + buildIndexProbe(v, nCol, pIdx, regBase, r1); + if( !bRev ){ int op = btmEq ? OP_MoveGe : OP_MoveGt; - sqlite3VdbeAddOp2(v, op, iIdxCur, nxt); + sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); + sqlite3ReleaseTempReg(pParse, r1); } }else if( bRev ){ testOp = OP_Noop; @@ -2546,20 +2544,21 @@ WhereInfo *sqlite3WhereBegin( */ start = sqlite3VdbeCurrentAddr(v); if( testOp!=OP_Noop ){ - sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); - sqlite3VdbeAddOp2(v, testOp, iIdxCur, nxt); + sqlite3VdbeAddOp3(v, testOp, iIdxCur, nxt, pLevel->iMem); if( (topEq && !bRev) || (!btmEq && bRev) ){ sqlite3VdbeChangeP5(v, 1); } } + r1 = sqlite3GetTempReg(pParse); if( topLimit | btmLimit ){ - sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, nEq); - sqlite3VdbeAddOp2(v, OP_StackIsNull, 1, cont); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1); + sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont); } if( !omitTable ){ - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, 0); - sqlite3VdbeAddOp2(v, OP_MoveGe, iCur, 0); + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); + sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); } + sqlite3ReleaseTempReg(pParse, r1); /* Record the instruction used to terminate the loop. */ @@ -2573,11 +2572,13 @@ WhereInfo *sqlite3WhereBegin( 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. */ - codeAllEqualityTerms(pParse, pLevel, &wc, notReady); + regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1); nxt = pLevel->nxt; if( (obflag==ORDERBY_MIN) @@ -2585,21 +2586,17 @@ WhereInfo *sqlite3WhereBegin( && (pIdx->nColumn>nEq) && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) ){ - int h; isMinQuery = 1; - for(h=0; hiMem); - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); - buildIndexProbe(v, nEq+1, pIdx); + buildIndexProbe(v, nEq, pIdx, regBase, pLevel->iMem); + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + r1 = ++pParse->nMem; + buildIndexProbe(v, nEq+1, pIdx, regBase, r1); }else{ /* Generate a single key that will be used to both start and ** terminate the search */ - buildIndexProbe(v, nEq, pIdx); - sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem); + r1 = pLevel->iMem; + buildIndexProbe(v, nEq, pIdx, regBase, r1); } /* Generate code (1) to move to the first matching element of the table. @@ -2609,21 +2606,33 @@ WhereInfo *sqlite3WhereBegin( ** iteration of the scan to see if the scan has finished. */ if( bRev ){ /* Scan in reverse order */ - sqlite3VdbeAddOp2(v, (isMinQuery?OP_MoveLt:OP_MoveLe), iIdxCur, nxt); - start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); - sqlite3VdbeAddOp2(v, OP_IdxLT, iIdxCur, nxt); + 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 */ - sqlite3VdbeAddOp2(v, (isMinQuery?OP_MoveGt:OP_MoveGe), iIdxCur, nxt); - start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); - sqlite3VdbeAddOp2(v, OP_IdxGE, iIdxCur, nxt); + 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 ){ - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, 0); - sqlite3VdbeAddOp2(v, OP_MoveGe, iCur, 0); + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); + sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); + sqlite3ReleaseTempReg(pParse, r1); } pLevel->p1 = iIdxCur; pLevel->p2 = start; diff --git a/test/tester.tcl b/test/tester.tcl index 949856a2a0..6c9aaeebbe 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.100 2008/01/16 17:46:38 drh Exp $ +# $Id: tester.tcl,v 1.101 2008/01/17 02:36:28 drh Exp $ set tcl_precision 15 @@ -603,7 +603,7 @@ proc cksum {{db db}} { # database $db. If the checksum of two databases is the same, and the # integrity-check passes for both, the two databases are identical. # -proc allcksum {db} { +proc allcksum {{db db}} { set ret [list] ifcapable tempdb { set sql { diff --git a/test/vacuum.test b/test/vacuum.test index 0576bb67c9..580f0fcad2 100644 --- a/test/vacuum.test +++ b/test/vacuum.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # -# $Id: vacuum.test,v 1.39 2008/01/16 17:46:38 drh Exp $ +# $Id: vacuum.test,v 1.40 2008/01/17 02:36:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -49,14 +49,14 @@ do_test vacuum-1.1 { DROP TABLE t2; } set ::size1 [file size test.db] - set ::cksum [allcksum] + set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-1.2 { execsql { VACUUM; } - allcksum + cksum } $cksum ifcapable vacuum { do_test vacuum-1.3 { @@ -84,14 +84,14 @@ do_test vacuum-1.4 { } execsql $sql_script set ::size1 [file size test.db] - set ::cksum [allcksum] + set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-1.5 { execsql { VACUUM; } - allcksum + cksum } $cksum ifcapable vacuum { @@ -119,17 +119,17 @@ do_test vacuum-2.2 { DROP TABLE t4; DROP TABLE t5; } db2 - set ::cksum [allcksum db2] + set ::cksum [cksum db2] catchsql { VACUUM } } {0 {}} do_test vacuum-2.3 { - allcksum + cksum } $cksum do_test vacuum-2.4 { catch {db2 eval {SELECT count(*) FROM sqlite_master}} - allcksum db2 + cksum db2 } $cksum # Make sure the schema cookie is incremented by vacuum. @@ -308,28 +308,28 @@ ifcapable {autoinc} { INSERT INTO autoinc(b) VALUES('there'); DELETE FROM autoinc; } - set ::cksum [allcksum] + set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-9.2 { execsql { VACUUM; } - allcksum + cksum } $::cksum do_test vacuum-9.3 { execsql { INSERT INTO autoinc(b) VALUES('one'); INSERT INTO autoinc(b) VALUES('two'); } - set ::cksum [allcksum] + set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-9.4 { execsql { VACUUM; } - allcksum + cksum } $::cksum } diff --git a/test/vacuum2.test b/test/vacuum2.test index c0a7c7f1eb..5c46d0c899 100644 --- a/test/vacuum2.test +++ b/test/vacuum2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # -# $Id: vacuum2.test,v 1.6 2008/01/16 17:46:38 drh Exp $ +# $Id: vacuum2.test,v 1.7 2008/01/17 02:36:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -76,9 +76,9 @@ do_test vacuum2-3.1 { } expr {[file size test.db]/$pageSize} } {3} -set cksum [allcksum] +set cksum [cksum] do_test vacuum2-3.2 { - allcksum db2 + cksum db2 } $cksum # Convert the database to an autovacuumed database. @@ -90,10 +90,10 @@ do_test vacuum2-3.3 { expr {[file size test.db]/$pageSize} } {4} do_test vacuum2-3.4 { - allcksum db2 + cksum db2 } $cksum do_test vacuum2-3.5 { - allcksum + cksum } $cksum do_test vacuum2-3.6 { execsql {PRAGMA integrity_check} db2 @@ -111,10 +111,10 @@ do_test vacuum2-3.13 { expr {[file size test.db]/$pageSize} } {3} do_test vacuum2-3.14 { - allcksum db2 + cksum db2 } $cksum do_test vacuum2-3.15 { - allcksum + cksum } $cksum do_test vacuum2-3.16 { execsql {PRAGMA integrity_check} db2