]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
New Next opcode and indexing style implemented. (CVS 304)
authordrh <drh@noemail.net>
Wed, 7 Nov 2001 16:48:26 +0000 (16:48 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Nov 2001 16:48:26 +0000 (16:48 +0000)
FossilOrigin-Name: decbeb9151885fee473b3fa58c8cf78a2338d2d8

manifest
manifest.uuid
src/build.c
src/delete.c
src/insert.c
src/main.c
src/select.c
src/sqliteInt.h
src/vdbe.c
src/vdbe.h
src/where.c

index aa73e89149c04d3915412ae137b87208fe980a7d..e73b7b1dfc14c03bcb25e5464f73088da197526e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Incremental\supdate.\s\sWe\sare\sin\sthe\smiddle\sof\smodifying\sthe\sindex\ssystem\nto\ssupport\srange\squeries\swithout\sdoing\sa\scomplete\stable\sscan.\s(CVS\s303)
-D 2001-11-07T14:22:00
+C New\sNext\sopcode\sand\sindexing\sstyle\simplemented.\s(CVS\s304)
+D 2001-11-07T16:48:27
 F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
 F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -21,13 +21,13 @@ F publish.sh 33cbe6798969f637698044023c139080e5d772a6
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c add522fad1b18c0face24e6f9f7468a6c696c5cc
 F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650
-F src/build.c b459cbe33ee617f46b1975f96ae605d3519583d9
-F src/delete.c 9cb0b1470e50881d3404f78af353df3ebb6399e5
+F src/build.c 40b7d14435e2cfc5298e8b7bab5e92ed26f42310
+F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2
 F src/expr.c 2dd0252ced345c1e64db015b94dc6b5d7a57eef3
 F src/hash.c d0110e6da70a5962e21575fccf8206f7d9d75e00
 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
-F src/insert.c 962f277340adc265fbde4dd952055df7ede4e67b
-F src/main.c e2ae5e14a3f936d5fa7e3d9d9477610b5f16e7eb
+F src/insert.c 3526be771a01035198bef28d8f370cbcab94f46d
+F src/main.c 0b0e7244c7af91613111d5b72387e33f8789ed72
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c 66b677479eae37e30bdfbe32deb0fe6a2efca983
 F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be
@@ -36,11 +36,11 @@ F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
 F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
-F src/select.c a97d3d27c544dc9a4849bfbad1cfa3e7c673bda9
+F src/select.c fa1c7144a9ad7ce3f16373b443bc25e764af4be7
 F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
-F src/sqliteInt.h fc2f7da1fee1e871b20b375c50c582065d891c7f
+F src/sqliteInt.h 555cff59458966ac16f044cc985f2267c75a606e
 F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
 F src/tclsqlite.c 4896e078495bf868742f5394dcf01c5efe5bea02
 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
@@ -49,9 +49,9 @@ F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
 F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
 F src/update.c b1e315e20b98a013d30fd9ff3b7d9dc4f29b39b3
 F src/util.c ac83973ecc647d3d3c58708f148442365abf9b94
-F src/vdbe.c 24306643bed5e19406735152ad68e98d598dcab0
-F src/vdbe.h a1170446638ce5b7f078279e640dcf91ec50de01
-F src/where.c 601f096f2a37ca688a775ca36d33534b13b876cb
+F src/vdbe.c 66e82eb4d042e34752ed23c3c13f921a895376af
+F src/vdbe.h da7c01076268f4fa1a17b7d6f27e21c3fd9a5d3f
+F src/where.c a6cac72314905902542c5239683d07fed27f6ee1
 F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
 F test/bigrow.test 9458134d67f81559845f934fdd6802fe19a68ad1
 F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
@@ -115,7 +115,7 @@ F www/speed.tcl 212a91d555384e01873160d6a189f1490c791bc2
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P 177012249ae93dbea4a11fb50faaae7912848bd0
-R 28881ea0807c6135a3c8ce43fbf768db
+P e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
+R 2ff273a13d7d9aa297cec267ea881bcc
 U drh
-Z bdd4c0f13b513e97b71388c7bea5ec3a
+Z 17c5246b4b0cf0179995e37754c3ee96
index 78c332e81c3ae89e0488a336bb5282189aea004a..0826b84defbb06df62233c9fe4431b7002872791 100644 (file)
@@ -1 +1 @@
-e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
\ No newline at end of file
+decbeb9151885fee473b3fa58c8cf78a2338d2d8
\ No newline at end of file
index c9fea4ecdfdc63418070fea92e8ec68bcb757b7c..69f392434c1db46ea05f3550b40655237cf43689 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.54 2001/11/07 14:22:00 drh Exp $
+** $Id: build.c,v 1.55 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -692,14 +692,14 @@ void sqliteDropTable(Parse *pParse, Token *pName){
   if( v ){
     static VdbeOp dropTable[] = {
       { OP_OpenWrite,  0, 2,        MASTER_NAME},
-      { OP_Rewind,     0, 0,        0},
+      { OP_Rewind,     0, ADDR(9),  0},
       { OP_String,     0, 0,        0}, /* 2 */
-      { OP_Next,       0, ADDR(9),  0}, /* 3 */
-      { OP_Dup,        0, 0,        0},
+      { OP_MemStore,   1, 1,        0},
+      { OP_MemLoad,    1, 0,        0}, /* 4 */
       { OP_Column,     0, 2,        0},
-      { OP_Ne,         0, ADDR(3),  0},
+      { OP_Ne,         0, ADDR(8),  0},
       { OP_Delete,     0, 0,        0},
-      { OP_Goto,       0, ADDR(3),  0},
+      { OP_Next,       0, ADDR(4),  0}, /* 8 */
       { OP_SetCookie,  0, 0,        0}, /* 9 */
       { OP_Close,      0, 0,        0},
     };
@@ -981,20 +981,16 @@ void sqliteCreateIndex(
     if( pTable ){
       sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
-      lbl1 = sqliteVdbeMakeLabel(v);
       lbl2 = sqliteVdbeMakeLabel(v);
-      sqliteVdbeAddOp(v, OP_Rewind, 2, 0);
-      sqliteVdbeResolveLabel(v, lbl1);
-      sqliteVdbeAddOp(v, OP_Next, 2, lbl2);
-      sqliteVdbeAddOp(v, OP_Recno, 2, 0);
+      sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
+      lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);
       for(i=0; i<pIndex->nColumn; i++){
         sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
       }
       sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
       sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->isUnique);
-      sqliteVdbeAddOp(v, OP_Goto, 0, lbl1);
+      sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
       sqliteVdbeResolveLabel(v, lbl2);
-      sqliteVdbeAddOp(v, OP_Noop, 0, 0);
       sqliteVdbeAddOp(v, OP_Close, 2, 0);
       sqliteVdbeAddOp(v, OP_Close, 1, 0);
     }
@@ -1043,15 +1039,16 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
   if( v ){
     static VdbeOp dropIndex[] = {
       { OP_OpenWrite,  0, 2,       MASTER_NAME},
-      { OP_Rewind,     0, 0,       0}, 
+      { OP_Rewind,     0, ADDR(10),0}, 
       { OP_String,     0, 0,       0}, /* 2 */
-      { OP_Next,       0, ADDR(8), 0}, /* 3 */
-      { OP_Dup,        0, 0,       0},
+      { OP_MemStore,   1, 1,       0},
+      { OP_MemLoad,    1, 0,       0}, /* 4 */
       { OP_Column,     0, 1,       0},
-      { OP_Ne,         0, ADDR(3), 0},
-      { OP_Delete,     0, 0,       0},
-      { OP_Destroy,    0, 0,       0}, /* 8 */
-      { OP_SetCookie,  0, 0,       0}, /* 9 */
+      { OP_Eq,         0, ADDR(9), 0},
+      { OP_Next,       0, ADDR(4), 0},
+      { OP_Goto,       0, ADDR(10),0},
+      { OP_Delete,     0, 0,       0}, /* 9 */
+      { OP_SetCookie,  0, 0,       0}, /* 10 */
       { OP_Close,      0, 0,       0},
     };
     int base;
@@ -1066,7 +1063,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
       base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
       sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
       changeCookie(db);
-      sqliteVdbeChangeP1(v, base+9, db->next_cookie);
+      sqliteVdbeChangeP1(v, base+10, db->next_cookie);
     }
     sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
     if( (db->flags & SQLITE_InTrans)==0 ){
index 5654b6ccef12e487e351a8c3cbea52505b980778..0b7a9c386f97cb0d72d9a40d9680041b5e657291 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.20 2001/11/07 14:22:00 drh Exp $
+** $Id: delete.c,v 1.21 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -106,10 +106,9 @@ void sqliteDeleteFrom(
       int addr;
       openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
       sqliteVdbeAddOp(v, openOp, 0, pTab->tnum);
-      sqliteVdbeAddOp(v, OP_Rewind, 0, 0);
-      addr = sqliteVdbeAddOp(v, OP_Next, 0, endOfLoop);
-      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
-      sqliteVdbeAddOp(v, OP_Goto, 0, addr);
+      sqliteVdbeAddOp(v, OP_Rewind, 0, sqliteVdbeCurrentAddr(v)+2);
+      addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
+      sqliteVdbeAddOp(v, OP_Next, 0, addr);
       sqliteVdbeResolveLabel(v, endOfLoop);
       sqliteVdbeAddOp(v, OP_Close, 0, 0);
     }
index 50e095797e117f86f3c486e3992d99013676de7a..a3faa2c41dc0eff2763d08fee4b7b8638050f53e 100644 (file)
@@ -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.25 2001/11/07 14:22:00 drh Exp $
+** $Id: insert.c,v 1.26 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -173,9 +173,9 @@ void sqliteInsert(
     if( db->flags & SQLITE_CountRows ){
       sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
     }
-    sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0);
     iBreak = sqliteVdbeMakeLabel(v);
-    iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak);
+    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
+    iCont = sqliteVdbeCurrentAddr(v);
   }
 
   /* Create a new entry in the table and fill it with data.
@@ -245,9 +245,13 @@ void sqliteInsert(
   /* The bottom of the loop, if the data source is a SELECT statement
   */
   if( srcTab>=0 ){
-    sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
+    sqliteVdbeAddOp(v, OP_Next, srcTab, iCont);
     sqliteVdbeResolveLabel(v, iBreak);
-    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
+    sqliteVdbeAddOp(v, OP_Close, srcTab, 0);
+  }
+  sqliteVdbeAddOp(v, OP_Close, base, 0);
+  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
+    sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
   }
   if( (db->flags & SQLITE_InTrans)==0 ){
     sqliteVdbeAddOp(v, OP_Commit, 0, 0);
index 672e5417768d06c5627ff20cde9268f6e31dfd8b..84dd60142070788a1e4dadbe905429c2797227fd 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.48 2001/11/03 23:57:09 drh Exp $
+** $Id: main.c,v 1.49 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -157,40 +157,37 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   */
   static VdbeOp initProg[] = {
     { OP_Open,     0, 2,  0},
-    { OP_Rewind,   0, 0,  0},
-    { OP_Next,     0, 12, 0},           /* 2 */
-    { OP_Column,   0, 0,  0},
+    { OP_Rewind,   0, 31, 0},
+    { OP_Column,   0, 0,  0},           /* 2 */
     { OP_String,   0, 0,  "meta"},
-    { OP_Ne,       0, 2,  0},
+    { OP_Ne,       0, 10, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
     { OP_Column,   0, 4,  0},
     { OP_Callback, 4, 0,  0},
-    { OP_Goto,     0, 2,  0},
-    { OP_Rewind,   0, 0,  0},           /* 12 */
-    { OP_Next,     0, 23, 0},           /* 13 */
-    { OP_Column,   0, 0,  0},
+    { OP_Next,     0, 2,  0},           /* 10 */
+    { OP_Rewind,   0, 31, 0},           /* 11 */
+    { OP_Column,   0, 0,  0},           /* 12 */
     { OP_String,   0, 0,  "table"},
-    { OP_Ne,       0, 13, 0},
+    { OP_Ne,       0, 20, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
     { OP_Column,   0, 4,  0},
     { OP_Callback, 4, 0,  0},
-    { OP_Goto,     0, 13, 0},
-    { OP_Rewind,   0, 0,  0},           /* 23 */
-    { OP_Next,     0, 34, 0},           /* 24 */
-    { OP_Column,   0, 0,  0},
+    { OP_Next,     0, 12, 0},           /* 20 */
+    { OP_Rewind,   0, 31, 0},           /* 21 */
+    { OP_Column,   0, 0,  0},           /* 22 */
     { OP_String,   0, 0,  "index"},
-    { OP_Ne,       0, 24, 0},
+    { OP_Ne,       0, 30, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
     { OP_Column,   0, 4,  0},
     { OP_Callback, 4, 0,  0},
-    { OP_Goto,     0, 24, 0},
-    { OP_String,   0, 0,  "meta"},      /* 34 */
+    { OP_Next,     0, 22, 0},           /* 30 */
+    { OP_String,   0, 0,  "meta"},      /* 31 */
     { OP_String,   0, 0,  "schema-cookie"},
     { OP_String,   0, 0,  0},
     { OP_ReadCookie,0,0,  0},
index 9ff90043e99d62336dc476b640cc25006795ad2f..b30172cb0ac9ca21b4cc81192f2bf1a463efb66d 100644 (file)
@@ -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.48 2001/11/07 14:22:00 drh Exp $
+** $Id: select.c,v 1.49 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -557,17 +557,19 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       ** it is that we currently need.
       */      
       if( eDest!=priorOp ){
-        int iCont, iBreak;
+        int iCont, iBreak, iStart;
         assert( p->pEList );
         generateColumnNames(pParse, 0, p->pEList);
-        sqliteVdbeAddOp(v, OP_Rewind, unionTab, 0);
         iBreak = sqliteVdbeMakeLabel(v);
-        iCont = sqliteVdbeAddOp(v, OP_Next, unionTab, iBreak);
+        iCont = sqliteVdbeMakeLabel(v);
+        sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak);
+        iStart = sqliteVdbeCurrentAddr(v);
         rc = selectInnerLoop(pParse, 0, unionTab, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
                              iCont, iBreak);
         if( rc ) return 1;
-        sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
+        sqliteVdbeResolveLabel(v, iCont);
+        sqliteVdbeAddOp(v, OP_Next, unionTab, iStart);
         sqliteVdbeResolveLabel(v, iBreak);
         sqliteVdbeAddOp(v, OP_Close, unionTab, 0);
         if( p->pOrderBy ){
@@ -578,7 +580,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
     }
     case TK_INTERSECT: {
       int tab1, tab2;
-      int iCont, iBreak;
+      int iCont, iBreak, iStart;
 
       /* INTERSECT is different from the others since it requires
       ** two temporary tables.  Hence it has its own case.  Begin
@@ -611,16 +613,17 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       */
       assert( p->pEList );
       generateColumnNames(pParse, 0, p->pEList);
-      sqliteVdbeAddOp(v, OP_Rewind, tab1, 0);
       iBreak = sqliteVdbeMakeLabel(v);
-      iCont = sqliteVdbeAddOp(v, OP_Next, tab1, iBreak);
-      sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
+      iCont = sqliteVdbeMakeLabel(v);
+      sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak);
+      iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
       sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont);
       rc = selectInnerLoop(pParse, 0, tab1, p->pEList->nExpr,
                              p->pOrderBy, -1, eDest, iParm, 
                              iCont, iBreak);
       if( rc ) return 1;
-      sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
+      sqliteVdbeResolveLabel(v, iCont);
+      sqliteVdbeAddOp(v, OP_Next, tab1, iStart);
       sqliteVdbeResolveLabel(v, iBreak);
       sqliteVdbeAddOp(v, OP_Close, tab2, 0);
       sqliteVdbeAddOp(v, OP_Close, tab1, 0);
index 1f170d91d7d796a15c9fe1156b3211ef9d5ce716..3f71491b4e51e177e46028cc600579f8824e7122 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.67 2001/11/06 04:00:19 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.68 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -139,6 +139,7 @@ typedef struct Parse Parse;
 typedef struct Token Token;
 typedef struct IdList IdList;
 typedef struct WhereInfo WhereInfo;
+typedef struct WhereLevel WhereLevel;
 typedef struct Select Select;
 typedef struct AggExpr AggExpr;
 
@@ -298,6 +299,21 @@ struct IdList {
   } *a;            /* One entry for each identifier on the list */
 };
 
+/*
+** For each nested loop in a WHERE clause implementation, the WhereInfo
+** structure contains a single instance of this structure.  This structure
+** is intended to be private the the where.c module and should not be
+** access or modified by other modules.
+*/
+struct WhereLevel {
+  int iMem;            /* Memory cell used by this level */
+  Index *pIdx;         /* Index used */
+  int iCur;            /* Cursor number used for this index */
+  int brk;             /* Jump here to break out of the loop */
+  int cont;            /* Jump here to continue with the next loop cycle */
+  int op, p1, p2;      /* Opcode used to terminate the loop */
+};
+
 /*
 ** The WHERE clause processing routine has two halves.  The
 ** first part does the start of the WHERE loop and the second
@@ -311,7 +327,8 @@ struct WhereInfo {
   int iContinue;       /* Jump here to continue with next record */
   int iBreak;          /* Jump here to break out of the loop */
   int base;            /* Index of first Open opcode */
-  Index *aIdx[32];     /* Indices used for each table */
+  int nLevel;          /* Number of nested loop */
+  WhereLevel a[1];     /* Information about each nest loop in the WHERE */
 };
 
 /*
index ba6fc566a584773c661717b89ad2395bd18da597..3475130e1bea20d13cd7b64f305b8a5f9c0d30c6 100644 (file)
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.94 2001/11/07 14:22:00 drh Exp $
+** $Id: vdbe.c,v 1.95 2001/11/07 16:48:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -64,8 +64,6 @@ struct Cursor {
   Bool keyAsData;       /* The OP_Column command works on key instead of data */
   Bool atFirst;         /* True if pointing to first entry */
   Btree *pBt;           /* Separate file holding temporary table */
-  char *zKey;           /* Key used in BeginIdx and NextIdx operators */
-  int nKey;             /* Number of bytes in zKey[] */
 };
 typedef struct Cursor Cursor;
 
@@ -277,6 +275,39 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
   return i;
 }
 
+/*
+** Create a new symbolic label for an instruction that has yet to be
+** coded.  The symbolic label is really just a negative number.  The
+** label can be used as the P2 value of an operation.  Later, when
+** the label is resolved to a specific address, the VDBE will scan
+** through its operation list and change all values of P2 which match
+** the label into the resolved address.
+**
+** The VDBE knows that a P2 value is a label because labels are
+** always negative and P2 values are suppose to be non-negative.
+** Hence, a negative P2 value is a label that has yet to be resolved.
+*/
+int sqliteVdbeMakeLabel(Vdbe *p){
+  int i;
+  i = p->nLabel++;
+  if( i>=p->nLabelAlloc ){
+    int *aNew;
+    p->nLabelAlloc = p->nLabelAlloc*2 + 10;
+    aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
+    if( aNew==0 ){
+      sqliteFree(p->aLabel);
+    }
+    p->aLabel = aNew;
+  }
+  if( p->aLabel==0 ){
+    p->nLabel = 0;
+    p->nLabelAlloc = 0;
+    return 0;
+  }
+  p->aLabel[i] = -1;
+  return -1-i;
+}
+
 /*
 ** Resolve label "x" to be the address of the next instruction to
 ** be inserted.
@@ -284,6 +315,8 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
 void sqliteVdbeResolveLabel(Vdbe *p, int x){
   int j;
   if( x<0 && (-x)<=p->nLabel && p->aOp ){
+    if( p->aLabel[-1-x]==p->nOp ) return;
+    assert( p->aLabel[-1-x]<0 );
     p->aLabel[-1-x] = p->nOp;
     for(j=0; j<p->nOp; j++){
       if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;
@@ -440,39 +473,6 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
   }
 }
 
-/*
-** Create a new symbolic label for an instruction that has yet to be
-** coded.  The symbolic label is really just a negative number.  The
-** label can be used as the P2 value of an operation.  Later, when
-** the label is resolved to a specific address, the VDBE will scan
-** through its operation list and change all values of P2 which match
-** the label into the resolved address.
-**
-** The VDBE knows that a P2 value is a label because labels are
-** always negative and P2 values are suppose to be non-negative.
-** Hence, a negative P2 value is a label that has yet to be resolved.
-*/
-int sqliteVdbeMakeLabel(Vdbe *p){
-  int i;
-  i = p->nLabel++;
-  if( i>=p->nLabelAlloc ){
-    int *aNew;
-    p->nLabelAlloc = p->nLabelAlloc*2 + 10;
-    aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
-    if( aNew==0 ){
-      sqliteFree(p->aLabel);
-    }
-    p->aLabel = aNew;
-  }
-  if( p->aLabel==0 ){
-    p->nLabel = 0;
-    p->nLabelAlloc = 0;
-    return 0;
-  }
-  p->aLabel[i] = -1;
-  return -1-i;
-}
-
 /*
 ** Reset an Agg structure.  Delete all its contents.
 */
@@ -721,9 +721,6 @@ static void cleanupCursor(Cursor *pCx){
   if( pCx->pCursor ){
     sqliteBtreeCloseCursor(pCx->pCursor);
   }
-  if( pCx->zKey ){
-    sqliteFree(pCx->zKey);
-  }
   if( pCx->pBt ){
     sqliteBtreeClose(pCx->pBt);
   }
@@ -843,29 +840,28 @@ static char *zOpName[] = { 0,
   "MoveTo",            "Fcnt",              "NewRecno",          "Put",
   "Distinct",          "Found",             "NotFound",          "Delete",
   "Column",            "KeyAsData",         "Recno",             "FullKey",
-  "Rewind",            "Next",              "NextN",             "Destroy",
-  "Clear",             "CreateIndex",       "CreateTable",       "Reorganize",
-  "BeginIdx",          "NextIdx",           "IdxPut",            "IdxDelete",
-  "IdxRecno",          "IdxGT",             "IdxGE",             "MemLoad",
-  "MemStore",          "ListWrite",         "ListRewind",        "ListRead",
-  "ListReset",         "SortPut",           "SortMakeRec",       "SortMakeKey",
-  "Sort",              "SortNext",          "SortCallback",      "SortReset",
-  "FileOpen",          "FileRead",          "FileColumn",        "AggReset",
-  "AggFocus",          "AggIncr",           "AggNext",           "AggSet",
-  "AggGet",            "SetInsert",         "SetFound",          "SetNotFound",
-  "MakeRecord",        "MakeKey",           "MakeIdxKey",        "IncrKey",
-  "Goto",              "If",                "Halt",              "ColumnCount",
-  "ColumnName",        "Callback",          "NullCallback",      "Integer",
-  "String",            "Pop",               "Dup",               "Pull",
-  "Add",               "AddImm",            "Subtract",          "Multiply",
-  "Divide",            "Remainder",         "BitAnd",            "BitOr",
-  "BitNot",            "ShiftLeft",         "ShiftRight",        "AbsValue",
-  "Precision",         "Min",               "Max",               "Like",
-  "Glob",              "Eq",                "Ne",                "Lt",
-  "Le",                "Gt",                "Ge",                "IsNull",
-  "NotNull",           "Negative",          "And",               "Or",
-  "Not",               "Concat",            "Noop",              "Strlen",
-  "Substr",            "Limit",           
+  "Rewind",            "Next",              "Destroy",           "Clear",
+  "CreateIndex",       "CreateTable",       "Reorganize",        "IdxPut",
+  "IdxDelete",         "IdxRecno",          "IdxGT",             "IdxGE",
+  "MemLoad",           "MemStore",          "ListWrite",         "ListRewind",
+  "ListRead",          "ListReset",         "SortPut",           "SortMakeRec",
+  "SortMakeKey",       "Sort",              "SortNext",          "SortCallback",
+  "SortReset",         "FileOpen",          "FileRead",          "FileColumn",
+  "AggReset",          "AggFocus",          "AggIncr",           "AggNext",
+  "AggSet",            "AggGet",            "SetInsert",         "SetFound",
+  "SetNotFound",       "MakeRecord",        "MakeKey",           "MakeIdxKey",
+  "IncrKey",           "Goto",              "If",                "Halt",
+  "ColumnCount",       "ColumnName",        "Callback",          "NullCallback",
+  "Integer",           "String",            "Pop",               "Dup",
+  "Pull",              "Add",               "AddImm",            "Subtract",
+  "Multiply",          "Divide",            "Remainder",         "BitAnd",
+  "BitOr",             "BitNot",            "ShiftLeft",         "ShiftRight",
+  "AbsValue",          "Precision",         "Min",               "Max",
+  "Like",              "Glob",              "Eq",                "Ne",
+  "Lt",                "Le",                "Gt",                "Ge",
+  "IsNull",            "NotNull",           "Negative",          "And",
+  "Or",                "Not",               "Concat",            "Noop",
+  "Strlen",            "Substr",            "Limit",           
 };
 
 /*
@@ -1043,6 +1039,8 @@ int sqliteVdbeExec(
   zStack = p->zStack;
   aStack = p->aStack;
   p->tos = -1;
+  p->iLimit = 0;
+  p->iOffset = 0;
 
   /* Initialize the aggregrate hash table.
   */
@@ -2929,36 +2927,11 @@ case OP_Rewind: {
 /* Opcode: Next P1 P2 *
 **
 ** Advance cursor P1 so that it points to the next key/data pair in its
-** table.  Or, if there are no more key/data pairs, jump to location P2.
-*/
-case OP_Next: {
-  int i = pOp->p1;
-  BtCursor *pCrsr;
-
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
-    if( !p->aCsr[i].atFirst ){
-      int res;
-      rc = sqliteBtreeNext(pCrsr, &res);
-      if( res ){
-        pc = pOp->p2 - 1;
-      }else{
-        p->nFetch++;
-      }
-    }
-    p->aCsr[i].atFirst = 0;
-    p->aCsr[i].recnoIsValid = 0;
-  }
-  break;
-}
-
-/* Opcode: NextN P1 P2 *
-**
-** Advance cursor P1 so that it points to the next key/data pair in its
 ** table or index.  If there are no more key/value pairs then fall through
 ** to the following instruction.  But if the cursor advance was successful,
 ** jump immediately to P2.
 */
-case OP_NextN: {
+case OP_Next: {
   int i = pOp->p1;
   BtCursor *pCrsr;
 
@@ -2974,92 +2947,6 @@ case OP_NextN: {
   break;
 }
 
-/* Opcode: BeginIdx P1 * *
-**
-** Begin searching an index for records with the key found on the
-** top of the stack.  The key on the top of the stack should be built
-** using the MakeKey opcode.  Subsequent calls to NextIdx will push
-** record numbers onto the stack until all records with the same key
-** have been returned.
-**
-** Note that the key for this opcode should be built using MakeKey
-** but the key used for PutIdx and DeleteIdx should be built using
-** MakeIdxKey.  The difference is that MakeIdxKey adds a 4-bytes
-** record number to the end of the key in order to specify a particular
-** entry in the index.  MakeKey omits the 4-byte record number.
-** The search that this BeginIdx instruction initiates will span all
-** entries in the index where the MakeKey generated key matches all
-** but the last four bytes of the MakeIdxKey generated key.
-*/
-case OP_BeginIdx: {
-  int i = pOp->p1;
-  int tos = p->tos;
-  int res, rx;
-  Cursor *pCrsr;
-  VERIFY( if( tos<0 ) goto not_enough_stack; )
-  if( i>=0 && i<p->nCursor && (pCrsr = &p->aCsr[i])->pCursor!=0 ){
-    if( Stringify(p, tos) ) goto no_mem;
-    if( pCrsr->zKey ) sqliteFree(pCrsr->zKey);
-    pCrsr->nKey = aStack[tos].n;
-    pCrsr->zKey = sqliteMalloc( pCrsr->nKey+1 );
-    if( pCrsr->zKey==0 ) goto no_mem;
-    memcpy(pCrsr->zKey, zStack[tos], aStack[tos].n);
-    pCrsr->zKey[aStack[tos].n] = 0;
-    rx = sqliteBtreeMoveto(pCrsr->pCursor, zStack[tos], aStack[tos].n, &res);
-    pCrsr->atFirst = rx==SQLITE_OK && res>0;
-    pCrsr->recnoIsValid = 0;
-  }
-  POPSTACK;
-  break;
-}
-
-/* Opcode: NextIdx P1 P2 *
-**
-** The P1 cursor points to an SQL index for which a BeginIdx operation
-** has been issued.  This operation retrieves the next record from that
-** cursor and verifies that the key on the record minus the last 4 bytes
-** matches the key that was pulled from the stack by the BeginIdx instruction.
-** If they match, then the last 4 bytes of the key on the record hold a record
-** number and that record number is extracted and pushed on the stack.
-** If the keys do not match, there is an immediate jump to instruction P2.
-*/
-case OP_NextIdx: {
-  int i = pOp->p1;
-  int tos = ++p->tos;
-  Cursor *pCrsr;
-  BtCursor *pCur;
-  int rx, res, size;
-
-  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
-  zStack[tos] = 0;
-  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = &p->aCsr[i])->pCursor!=0 ){
-    pCur = pCrsr->pCursor;
-    if( pCrsr->atFirst ){
-      pCrsr->atFirst = 0;
-      res = 0;
-    }else{
-      rx = sqliteBtreeNext(pCur, &res);
-      if( rx!=SQLITE_OK ) goto abort_due_to_error;
-    }
-    sqliteBtreeKeySize(pCur, &size);
-    if( res>0 || size!=pCrsr->nKey+sizeof(u32) ||
-      sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, 4, &res)!=SQLITE_OK
-      || res!=0
-    ){
-      pc = pOp->p2 - 1;
-      POPSTACK;
-    }else{
-      int recno;
-      sqliteBtreeKey(pCur, pCrsr->nKey, sizeof(u32), (char*)&recno);
-      recno = bigEndian(recno);
-      p->aCsr[i].lastRecno = aStack[tos].i = recno;
-      p->aCsr[i].recnoIsValid = 1;
-      aStack[tos].flags = STK_Int;
-    }
-  }
-  break;
-}
-
 /* Opcode: IdxPut P1 P2 P3
 **
 ** The top of the stack hold an SQL index key made using the
@@ -3197,6 +3084,7 @@ case OP_IdxGE: {
       pc = pOp->p2 - 1 ;
     }
   }
+  POPSTACK;
   break;
 }
 
@@ -3780,7 +3668,7 @@ case OP_MemStore: {
   if( pMem->s.flags & (STK_Static|STK_Dyn) ){
     if( pOp->p2==0 && (pMem->s.flags & STK_Dyn)!=0 ){
       pMem->z = sqliteMalloc( pMem->s.n );
-      if( pMem->z ) goto no_mem;
+      if( pMem->z==0 ) goto no_mem;
       memcpy(pMem->z, zStack[tos], pMem->s.n);
     }else{
       pMem->z = zStack[tos];
index 7d3aac15789b6ada4a7e328d748519078eb47fa1..9f69c32279e64318fe87865c8168a87d0691cdaf 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.34 2001/11/07 14:22:00 drh Exp $
+** $Id: vdbe.h,v 1.35 2001/11/07 16:48:28 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -96,111 +96,108 @@ typedef struct VdbeOp VdbeOp;
 #define OP_FullKey            24
 #define OP_Rewind             25
 #define OP_Next               26
-#define OP_NextN              27
-
-#define OP_Destroy            28
-#define OP_Clear              29
-#define OP_CreateIndex        30
-#define OP_CreateTable        31
-#define OP_Reorganize         32
-
-#define OP_BeginIdx           33
-#define OP_NextIdx            34
-#define OP_IdxPut             35
-#define OP_IdxDelete          36
-#define OP_IdxRecno           37
-#define OP_IdxGT              38
-#define OP_IdxGE              39
-
-#define OP_MemLoad            40
-#define OP_MemStore           41
-
-#define OP_ListWrite          42
-#define OP_ListRewind         43
-#define OP_ListRead           44
-#define OP_ListReset          45
-
-#define OP_SortPut            46
-#define OP_SortMakeRec        47
-#define OP_SortMakeKey        48
-#define OP_Sort               49
-#define OP_SortNext           50
-#define OP_SortCallback       51
-#define OP_SortReset          52
-
-#define OP_FileOpen           53
-#define OP_FileRead           54
-#define OP_FileColumn         55
-
-#define OP_AggReset           56
-#define OP_AggFocus           57
-#define OP_AggIncr            58
-#define OP_AggNext            59
-#define OP_AggSet             60
-#define OP_AggGet             61
-
-#define OP_SetInsert          62
-#define OP_SetFound           63
-#define OP_SetNotFound        64
-
-#define OP_MakeRecord         65
-#define OP_MakeKey            66
-#define OP_MakeIdxKey         67
-#define OP_IncrKey            68
-
-#define OP_Goto               69
-#define OP_If                 70
-#define OP_Halt               71
-
-#define OP_ColumnCount        72
-#define OP_ColumnName         73
-#define OP_Callback           74
-#define OP_NullCallback       75
-
-#define OP_Integer            76
-#define OP_String             77
-#define OP_Pop                78
-#define OP_Dup                79
-#define OP_Pull               80
-
-#define OP_Add                81
-#define OP_AddImm             82
-#define OP_Subtract           83
-#define OP_Multiply           84
-#define OP_Divide             85
-#define OP_Remainder          86
-#define OP_BitAnd             87
-#define OP_BitOr              88
-#define OP_BitNot             89
-#define OP_ShiftLeft          90
-#define OP_ShiftRight         91
-#define OP_AbsValue           92
-#define OP_Precision          93
-#define OP_Min                94
-#define OP_Max                95
-#define OP_Like               96
-#define OP_Glob               97
-#define OP_Eq                 98
-#define OP_Ne                 99
-#define OP_Lt                100
-#define OP_Le                101
-#define OP_Gt                102
-#define OP_Ge                103
-#define OP_IsNull            104
-#define OP_NotNull           105
-#define OP_Negative          106
-#define OP_And               107
-#define OP_Or                108
-#define OP_Not               109
-#define OP_Concat            110
-#define OP_Noop              111
-
-#define OP_Strlen            112
-#define OP_Substr            113
-
-#define OP_Limit             114
-
-#define OP_MAX               114
+
+#define OP_Destroy            27
+#define OP_Clear              28
+#define OP_CreateIndex        29
+#define OP_CreateTable        30
+#define OP_Reorganize         31
+
+#define OP_IdxPut             32
+#define OP_IdxDelete          33
+#define OP_IdxRecno           34
+#define OP_IdxGT              35
+#define OP_IdxGE              36
+
+#define OP_MemLoad            37
+#define OP_MemStore           38
+
+#define OP_ListWrite          39
+#define OP_ListRewind         40
+#define OP_ListRead           41
+#define OP_ListReset          42
+
+#define OP_SortPut            43
+#define OP_SortMakeRec        44
+#define OP_SortMakeKey        45
+#define OP_Sort               46
+#define OP_SortNext           47
+#define OP_SortCallback       48
+#define OP_SortReset          49
+
+#define OP_FileOpen           50
+#define OP_FileRead           51
+#define OP_FileColumn         52
+
+#define OP_AggReset           53
+#define OP_AggFocus           54
+#define OP_AggIncr            55
+#define OP_AggNext            56
+#define OP_AggSet             57
+#define OP_AggGet             58
+
+#define OP_SetInsert          59
+#define OP_SetFound           60
+#define OP_SetNotFound        61
+
+#define OP_MakeRecord         62
+#define OP_MakeKey            63
+#define OP_MakeIdxKey         64
+#define OP_IncrKey            65
+
+#define OP_Goto               66
+#define OP_If                 67
+#define OP_Halt               68
+
+#define OP_ColumnCount        69
+#define OP_ColumnName         70
+#define OP_Callback           71
+#define OP_NullCallback       72
+
+#define OP_Integer            73
+#define OP_String             74
+#define OP_Pop                75
+#define OP_Dup                76
+#define OP_Pull               77
+
+#define OP_Add                78
+#define OP_AddImm             79
+#define OP_Subtract           80
+#define OP_Multiply           81
+#define OP_Divide             82
+#define OP_Remainder          83
+#define OP_BitAnd             84
+#define OP_BitOr              85
+#define OP_BitNot             86
+#define OP_ShiftLeft          87
+#define OP_ShiftRight         88
+#define OP_AbsValue           89
+#define OP_Precision          90
+#define OP_Min                91
+#define OP_Max                92
+#define OP_Like               93
+#define OP_Glob               94
+#define OP_Eq                 95
+#define OP_Ne                 96
+#define OP_Lt                 97
+#define OP_Le                 98
+#define OP_Gt                 99
+#define OP_Ge                100
+#define OP_IsNull            101
+#define OP_NotNull           102
+#define OP_Negative          103
+#define OP_And               104
+#define OP_Or                105
+#define OP_Not               106
+#define OP_Concat            107
+#define OP_Noop              108
+
+#define OP_Strlen            109
+#define OP_Substr            110
+
+#define OP_Limit             111
+
+#define OP_MAX               111
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
index a18db244d35797afdb59e79b7645a9388e1f5adc..8e5b41a600a68c76e3e90dbd7ab6d9e8fc0628e7 100644 (file)
@@ -13,7 +13,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.24 2001/11/04 18:32:48 drh Exp $
+** $Id: where.c,v 1.25 2001/11/07 16:48:28 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -147,17 +147,17 @@ WhereInfo *sqliteWhereBegin(
   int loopMask;        /* One bit set for each outer loop */
   int haveKey;         /* True if KEY is on the stack */
   int base;            /* First available index for OP_Open opcodes */
-  Index *aIdx[32];     /* Index to use on each nested loop.  */
+  int nCur;            /* Next unused cursor number */
   int aDirect[32];     /* If TRUE, then index this table using ROWID */
   ExprInfo aExpr[50];  /* The WHERE clause is divided into these expressions */
 
-  /* Allocate space for aOrder[]. */
+  /* Allocate space for aOrder[] and aiMem[]. */
   aOrder = sqliteMalloc( sizeof(int) * pTabList->nId );
 
   /* Allocate and initialize the WhereInfo structure that will become the
   ** return value.
   */
-  pWInfo = sqliteMalloc( sizeof(WhereInfo) );
+  pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nId*sizeof(WhereLevel) );
   if( sqlite_malloc_failed ){
     sqliteFree(aOrder);
     sqliteFree(pWInfo);
@@ -166,6 +166,7 @@ WhereInfo *sqliteWhereBegin(
   pWInfo->pParse = pParse;
   pWInfo->pTabList = pTabList;
   base = pWInfo->base = pParse->nTab;
+  nCur = base + pTabList->nId;
 
   /* Split the WHERE clause into as many as 32 separate subexpressions
   ** where each subexpression is separated by an AND operator.  Any additional
@@ -197,8 +198,8 @@ WhereInfo *sqliteWhereBegin(
   }
 
   /* Figure out what index to use (if any) for each nested loop.
-  ** Make aIdx[i] point to the index to use for the i-th nested loop
-  ** where i==0 is the outer loop and i==pTabList->nId-1 is the inner
+  ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
+  ** loop where i==0 is the outer loop and i==pTabList->nId-1 is the inner
   ** loop.  If the expression uses only the ROWID field, then set
   ** aDirect[i] to 1.
   **
@@ -206,7 +207,7 @@ WhereInfo *sqliteWhereBegin(
   ** first 32 tables are candidates for indices.
   */
   loopMask = 0;
-  for(i=0; i<pTabList->nId && i<ARRAYSIZE(aIdx); i++){
+  for(i=0; i<pTabList->nId && i<ARRAYSIZE(aDirect); i++){
     int j;
     int idx = aOrder[i];
     Table *pTab = pTabList->a[idx].pTab;
@@ -232,7 +233,7 @@ WhereInfo *sqliteWhereBegin(
     }
     if( aDirect[i] ){
       loopMask |= 1<<idx;
-      aIdx[i] = 0;
+      pWInfo->a[i].pIdx = 0;
       continue;
     }
 
@@ -278,11 +279,14 @@ WhereInfo *sqliteWhereBegin(
         }
       }
     }
-    aIdx[i] = pBestIdx;
+    pWInfo->a[i].pIdx = pBestIdx;
     loopMask |= 1<<idx;
+    if( pBestIdx ){
+      pWInfo->a[i].iCur = nCur++;
+    }
   }
 
-  /* Open all tables in the pTabList and all indices in aIdx[].
+  /* Open all tables in the pTabList and all indices used by those tables.
   */
   for(i=0; i<pTabList->nId; i++){
     int openOp;
@@ -297,25 +301,25 @@ WhereInfo *sqliteWhereBegin(
       sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
       pParse->schemaVerified = 1;
     }
-    if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
-      sqliteVdbeAddOp(v, openOp, base+pTabList->nId+i, aIdx[i]->tnum);
-      sqliteVdbeChangeP3(v, -1, aIdx[i]->zName, P3_STATIC);
+    if( pWInfo->a[i].pIdx!=0 ){
+      sqliteVdbeAddOp(v, openOp, pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
+      sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
     }
   }
-  memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));
 
   /* Generate the code to do the search
   */
-  pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);
   loopMask = 0;
+  pWInfo->iBreak = sqliteVdbeMakeLabel(v);
   for(i=0; i<pTabList->nId; i++){
     int j, k;
     int idx = aOrder[i];
     int goDirect;
     Index *pIdx;
+    WhereLevel *pLevel = &pWInfo->a[i];
 
-    if( i<ARRAYSIZE(aIdx) ){
-      pIdx = aIdx[i];
+    if( i<ARRAYSIZE(aDirect) ){
+      pIdx = pLevel->pIdx;
       goDirect = aDirect[i];
     }else{
       pIdx = 0;
@@ -346,25 +350,33 @@ WhereInfo *sqliteWhereBegin(
         }
       }
       sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
+      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+      cont = pLevel->cont = brk;
       if( i==pTabList->nId-1 && pushKey ){
         haveKey = 1;
       }else{
         sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk);
         haveKey = 0;
       }
+      pLevel->op = OP_Noop;
     }else if( pIdx==0 ){
       /* Case 2:  There was no usable index.  We must do a complete
       ** scan of the table.
       */
-      sqliteVdbeAddOp(v, OP_Rewind, base+idx, 0);
-      cont = sqliteVdbeMakeLabel(v);
-      sqliteVdbeResolveLabel(v, cont);
-      sqliteVdbeAddOp(v, OP_Next, base+idx, brk);
+      int start;
+
+      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
+      sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
+      start = sqliteVdbeCurrentAddr(v);
+      pLevel->op = OP_Next;
+      pLevel->p1 = base+idx;
+      pLevel->p2 = start;
       haveKey = 0;
     }else{
       /* Case 3:  We do have a usable index in pIdx.
       */
-      cont = sqliteVdbeMakeLabel(v);
+      int start;
       for(j=0; j<pIdx->nColumn; j++){
         for(k=0; k<nExpr; k++){
           if( aExpr[k].p==0 ) continue;
@@ -386,16 +398,24 @@ WhereInfo *sqliteWhereBegin(
           }
         }
       }
+      pLevel->iMem = pParse->nMem++;
+      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
+      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
       sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0);
-      sqliteVdbeAddOp(v, OP_BeginIdx, base+pTabList->nId+i, 0);
-      sqliteVdbeResolveLabel(v, cont);
-      sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk);
+      sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+      sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
+      start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
+      sqliteVdbeAddOp(v, OP_IdxGT, pLevel->iCur, brk);
+      sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
       if( i==pTabList->nId-1 && pushKey ){
         haveKey = 1;
       }else{
         sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
         haveKey = 0;
       }
+      pLevel->op = OP_Next;
+      pLevel->p1 = pLevel->iCur;
+      pLevel->p2 = start;
     }
     loopMask |= 1<<idx;
 
@@ -429,22 +449,25 @@ WhereInfo *sqliteWhereBegin(
 void sqliteWhereEnd(WhereInfo *pWInfo){
   Vdbe *v = pWInfo->pParse->pVdbe;
   int i;
-  int brk = pWInfo->iBreak;
   int base = pWInfo->base;
+  WhereLevel *pLevel;
 
-  sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue);
+  for(i=pWInfo->pTabList->nId-1; i>=0; i--){
+    pLevel = &pWInfo->a[i];
+    sqliteVdbeResolveLabel(v, pLevel->cont);
+    if( pLevel->op!=OP_Noop ){
+      sqliteVdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
+    }
+    sqliteVdbeResolveLabel(v, pLevel->brk);
+  }
+  sqliteVdbeResolveLabel(v, pWInfo->iBreak);
   for(i=0; i<pWInfo->pTabList->nId; i++){
-    sqliteVdbeResolveLabel(v, brk);
+    pLevel = &pWInfo->a[i];
     sqliteVdbeAddOp(v, OP_Close, base+i, 0);
-    brk = 0;
-    if( i<ARRAYSIZE(pWInfo->aIdx) && pWInfo->aIdx[i]!=0 ){
-      sqliteVdbeAddOp(v, OP_Close, base+pWInfo->pTabList->nId+i, 0);
+    if( pLevel->pIdx!=0 ){
+      sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0);
     }
   }
-  if( brk!=0 ){
-    sqliteVdbeResolveLabel(v, brk);
-    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
-  }
   sqliteFree(pWInfo);
   return;
 }