diff --git a/manifest b/manifest index aa73e89149..e73b7b1dfc 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 78c332e81c..0826b84def 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0 \ No newline at end of file +decbeb9151885fee473b3fa58c8cf78a2338d2d8 \ No newline at end of file diff --git a/src/build.c b/src/build.c index c9fea4ecdf..69f392434c 100644 --- a/src/build.c +++ b/src/build.c @@ -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 @@ -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; inColumn; 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 ){ diff --git a/src/delete.c b/src/delete.c index 5654b6ccef..0b7a9c386f 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 ** 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); } diff --git a/src/insert.c b/src/insert.c index 50e095797e..a3faa2c41d 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.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); diff --git a/src/main.c b/src/main.c index 672e541776..84dd601420 100644 --- a/src/main.c +++ b/src/main.c @@ -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}, diff --git a/src/select.c b/src/select.c index 9ff90043e9..b30172cb0a 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.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); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1f170d91d7..3f71491b4e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */ }; /* diff --git a/src/vdbe.c b/src/vdbe.c index ba6fc566a5..3475130e1b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 @@ -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; jnOp; 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 && inCursor && ) (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 && inCursor && (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 && inCursor && ) (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]; diff --git a/src/vdbe.h b/src/vdbe.h index 7d3aac1578..9f69c32279 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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_Destroy 27 +#define OP_Clear 28 +#define OP_CreateIndex 29 +#define OP_CreateTable 30 +#define OP_Reorganize 31 -#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_IdxPut 32 +#define OP_IdxDelete 33 +#define OP_IdxRecno 34 +#define OP_IdxGT 35 +#define OP_IdxGE 36 -#define OP_MemLoad 40 -#define OP_MemStore 41 +#define OP_MemLoad 37 +#define OP_MemStore 38 -#define OP_ListWrite 42 -#define OP_ListRewind 43 -#define OP_ListRead 44 -#define OP_ListReset 45 +#define OP_ListWrite 39 +#define OP_ListRewind 40 +#define OP_ListRead 41 +#define OP_ListReset 42 -#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_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 53 -#define OP_FileRead 54 -#define OP_FileColumn 55 +#define OP_FileOpen 50 +#define OP_FileRead 51 +#define OP_FileColumn 52 -#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_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 62 -#define OP_SetFound 63 -#define OP_SetNotFound 64 +#define OP_SetInsert 59 +#define OP_SetFound 60 +#define OP_SetNotFound 61 -#define OP_MakeRecord 65 -#define OP_MakeKey 66 -#define OP_MakeIdxKey 67 -#define OP_IncrKey 68 +#define OP_MakeRecord 62 +#define OP_MakeKey 63 +#define OP_MakeIdxKey 64 +#define OP_IncrKey 65 -#define OP_Goto 69 -#define OP_If 70 -#define OP_Halt 71 +#define OP_Goto 66 +#define OP_If 67 +#define OP_Halt 68 -#define OP_ColumnCount 72 -#define OP_ColumnName 73 -#define OP_Callback 74 -#define OP_NullCallback 75 +#define OP_ColumnCount 69 +#define OP_ColumnName 70 +#define OP_Callback 71 +#define OP_NullCallback 72 -#define OP_Integer 76 -#define OP_String 77 -#define OP_Pop 78 -#define OP_Dup 79 -#define OP_Pull 80 +#define OP_Integer 73 +#define OP_String 74 +#define OP_Pop 75 +#define OP_Dup 76 +#define OP_Pull 77 -#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_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 112 -#define OP_Substr 113 +#define OP_Strlen 109 +#define OP_Substr 110 -#define OP_Limit 114 +#define OP_Limit 111 -#define OP_MAX 114 +#define OP_MAX 111 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/src/where.c b/src/where.c index a18db244d3..8e5b41a600 100644 --- a/src/where.c +++ b/src/where.c @@ -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; inId && inId && ia[idx].pTab; @@ -232,7 +233,7 @@ WhereInfo *sqliteWhereBegin( } if( aDirect[i] ){ loopMask |= 1<a[i].pIdx = 0; continue; } @@ -278,11 +279,14 @@ WhereInfo *sqliteWhereBegin( } } } - aIdx[i] = pBestIdx; + pWInfo->a[i].pIdx = pBestIdx; loopMask |= 1<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; inId; i++){ int openOp; @@ -297,25 +301,25 @@ WhereInfo *sqliteWhereBegin( sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); pParse->schemaVerified = 1; } - if( inId+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; inId; i++){ int j, k; int idx = aOrder[i]; int goDirect; Index *pIdx; + WhereLevel *pLevel = &pWInfo->a[i]; - if( ipIdx; 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; jnColumn; j++){ for(k=0; kiMem = 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<pParse->pVdbe; int i; - int brk = pWInfo->iBreak; int base = pWInfo->base; + WhereLevel *pLevel; - sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue); - for(i=0; ipTabList->nId; i++){ - sqliteVdbeResolveLabel(v, brk); - sqliteVdbeAddOp(v, OP_Close, base+i, 0); - brk = 0; - if( iaIdx) && pWInfo->aIdx[i]!=0 ){ - sqliteVdbeAddOp(v, OP_Close, base+pWInfo->pTabList->nId+i, 0); + 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); } - if( brk!=0 ){ - sqliteVdbeResolveLabel(v, brk); - sqliteVdbeAddOp(v, OP_Noop, 0, 0); + sqliteVdbeResolveLabel(v, pWInfo->iBreak); + for(i=0; ipTabList->nId; i++){ + pLevel = &pWInfo->a[i]; + sqliteVdbeAddOp(v, OP_Close, base+i, 0); + if( pLevel->pIdx!=0 ){ + sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0); + } } sqliteFree(pWInfo); return;