1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

VDBE cursors numbers for tables in a join do not have to be consecutive.

This is one step on the road to fixing ticket #272. (CVS 947)

FossilOrigin-Name: be7aed2011b4af868b6a0c370c3d41354ae0cdf4
This commit is contained in:
drh
2003-05-02 14:32:12 +00:00
parent 56e452cf3a
commit 6a3ea0e6ef
15 changed files with 315 additions and 322 deletions

View File

@ -1,5 +1,5 @@
C Correctly\screate\san\sindex\sthat\suses\san\sINTEGER\sPRIMARY\sKEY\sas\sone\sof\scolumns\nto\sbe\sindexed.\s(CVS\s946) C VDBE\scursors\snumbers\sfor\stables\sin\sa\sjoin\sdo\snot\shave\sto\sbe\sconsecutive.\nThis\sis\sone\sstep\son\sthe\sroad\sto\sfixing\sticket\s#272.\s(CVS\s947)
D 2003-05-01T16:56:03 D 2003-05-02T14:32:13
F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -20,19 +20,19 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183 F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
F src/auth.c 3be3c7434592117f049703966b940e0b07088ae2 F src/auth.c 53b8923f17f364af84501fa99dc00c779913a26d
F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d
F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d
F src/build.c d35b7a6595af2ab07083b7f63bd5d22578b3c189 F src/build.c e24461d42381a36de88de6af06c03d9f14588705
F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263 F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263
F src/delete.c 0f7c26aaebc417ad66a2a1099e59cc4056512c31 F src/delete.c f9536a75b444a21f11b7a1bc0fb8c876f691b013
F src/encode.c faf03741efe921755ec371cf4a6984536de00042 F src/encode.c faf03741efe921755ec371cf4a6984536de00042
F src/expr.c 46e2bb93abd6c70e67c8cdc5d92fdcd0b95498f3 F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616
F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605 F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c 19882be1edc4b1629b8f3097e2615164f2c9cecb F src/insert.c c230a8c216f6788095d46f0e270406a93aae45af
F src/main.c 5265058c9a598b4714dc9e528152b81fcb31e7ad F src/main.c 5265058c9a598b4714dc9e528152b81fcb31e7ad
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1 F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1
@ -43,11 +43,11 @@ F src/parse.y 39b5240cb78047dc56d6d37c398baed7ba556779
F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5 F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c d1c876b9078894bc956cf1a5b38abd1a5abaf70b F src/select.c 493360f3003719ad61d49863c4f5db0bad9022cb
F src/shell.c 6f59240f69e65a1c4e1d06492eb9238092defc34 F src/shell.c 6f59240f69e65a1c4e1d06492eb9238092defc34
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
F src/sqliteInt.h faf133e1441b7c7b93ad5d8a58201d4849033b75 F src/sqliteInt.h a3d84942dacaf72fbe1426adfbd37e8cf5f57e97
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325 F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
@ -55,13 +55,13 @@ F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
F src/tokenize.c 067d1a477a94af7712ca74e09aaa6bd0f7299527 F src/tokenize.c 067d1a477a94af7712ca74e09aaa6bd0f7299527
F src/trigger.c 62d1e1b837a98f1fa7511c77977d51c8516ddb65 F src/trigger.c 8ee811986080de60d9d883ad96daffea82014f27
F src/update.c f40376ed2e092a7040c6fc6fa0add59fad5c5e76 F src/update.c dc3b680b4cf2cb6d839950b68d632850746639b9
F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c
F src/vacuum.c 14ac3073203fa021e01ffe33db56968ad79a8344 F src/vacuum.c 14ac3073203fa021e01ffe33db56968ad79a8344
F src/vdbe.c 48098080d2b5d35d4cc28ac2a4855c7730f6ee7b F src/vdbe.c 829fa31c2169588db7a041950cb95c6bb75811a6
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21 F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
F src/where.c f632cd30f013163484a4d60c249d36fe31f5be12 F src/where.c ef11773a07cf075740378d7d1cbabf328146fdc9
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/attach.test b311c83e370e6b22b79a8279317039440ce64862 F test/attach.test b311c83e370e6b22b79a8279317039440ce64862
F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
@ -92,7 +92,7 @@ F test/limit.test 9ffb965a0f5bf7152187ef3d8d1249b96e5620bf
F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473 F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473
F test/main.test a028743affca67670e24c97527d1f4ad4bc2aad3 F test/main.test a028743affca67670e24c97527d1f4ad4bc2aad3
F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
F test/memdb.test 4494051bcf72df58d9c631a5bc1260cba2b021cc F test/memdb.test 3acf1453a5705d1aa524d3027667ca3d9c77c69f
F test/memleak.test a18e6810cae96d2f6f5136920267adbefc8e1e90 F test/memleak.test a18e6810cae96d2f6f5136920267adbefc8e1e90
F test/minmax.test b54ac3bc45460a4976b08ef363e05c032418726e F test/minmax.test b54ac3bc45460a4976b08ef363e05c032418726e
F test/misc1.test 865c907df58195364eaf2e69426e9674bc8d1a8c F test/misc1.test 865c907df58195364eaf2e69426e9674bc8d1a8c
@ -127,7 +127,7 @@ F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258 F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258
F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246 F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
F test/view.test d356f445d481c04ffa6036a4c61cb8ba70289f69 F test/view.test 8b3b0b30674865af2c87acbdf945e369f92012a5
F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4 F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/lemon.c 14fedcde9cf70aa6040b89de164cf8f56f92a4b9 F tool/lemon.c 14fedcde9cf70aa6040b89de164cf8f56f92a4b9
@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 20fcead42bc875f13eec52971530342ff00c5eda P 6d019e0baa3219614a9bc5b550a0f9fe3f7e731a
R 7ac507f145c490883ec534eb0c6164c6 R f7e61e2db6268bcec64f93ca941fa9e1
U drh U drh
Z a8877957a40cc5dcaf456e37a442b5a4 Z affbf408d9fd8c226a5447c7e8084f51

View File

@ -1 +1 @@
6d019e0baa3219614a9bc5b550a0f9fe3f7e731a be7aed2011b4af868b6a0c370c3d41354ae0cdf4

View File

@ -14,7 +14,7 @@
** systems that do not need this facility may omit it by recompiling ** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** the library with -DSQLITE_OMIT_AUTHORIZATION=1
** **
** $Id: auth.c,v 1.8 2003/04/25 17:52:11 drh Exp $ ** $Id: auth.c,v 1.9 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -76,8 +76,8 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
/* /*
** The pExpr should be a TK_COLUMN expression. The table referred to ** The pExpr should be a TK_COLUMN expression. The table referred to
** is in pTabList with an offset of base. Check to see if it is OK to read ** is in pTabList or else it is the NEW or OLD table of a trigger.
** this particular column. ** Check to see if it is OK to read this particular column.
** **
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
@ -86,8 +86,7 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
void sqliteAuthRead( void sqliteAuthRead(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
Expr *pExpr, /* The expression to check authorization on */ Expr *pExpr, /* The expression to check authorization on */
SrcList *pTabList, /* All table that pExpr might refer to */ SrcList *pTabList /* All table that pExpr might refer to */
int base /* Offset of pTabList relative to pExpr */
){ ){
sqlite *db = pParse->db; sqlite *db = pParse->db;
int rc; int rc;
@ -98,7 +97,9 @@ void sqliteAuthRead(
if( db->xAuth==0 ) return; if( db->xAuth==0 ) return;
assert( pExpr->op==TK_COLUMN ); assert( pExpr->op==TK_COLUMN );
iSrc = pExpr->iTable - base; for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
}
if( iSrc>=0 && iSrc<pTabList->nSrc ){ if( iSrc>=0 && iSrc<pTabList->nSrc ){
pTab = pTabList->a[iSrc].pTab; pTab = pTabList->a[iSrc].pTab;
}else{ }else{

View File

@ -23,7 +23,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.151 2003/05/01 16:56:03 drh Exp $ ** $Id: build.c,v 1.152 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -1767,7 +1767,7 @@ void sqliteCreateIndex(
if( pTab->iPKey==iCol ){ if( pTab->iPKey==iCol ){
sqliteVdbeAddOp(v, OP_Dup, i, 0); sqliteVdbeAddOp(v, OP_Dup, i, 0);
}else{ }else{
sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]); sqliteVdbeAddOp(v, OP_Column, 2, iCol);
} }
} }
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0); sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
@ -1993,7 +1993,7 @@ void sqliteSrcListAssignCursors(Parse *pParse, SrcList *pList){
int i; int i;
for(i=0; i<pList->nSrc; i++){ for(i=0; i<pList->nSrc; i++){
if( pList->a[i].iCursor<0 ){ if( pList->a[i].iCursor<0 ){
pList->a[i].iCursor = ++pParse->nTab; pList->a[i].iCursor = pParse->nTab++;
} }
} }
} }

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements. ** to handle DELETE FROM statements.
** **
** $Id: delete.c,v 1.55 2003/04/25 17:52:11 drh Exp $ ** $Id: delete.c,v 1.56 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -65,7 +65,7 @@ void sqliteDeleteFrom(
int i; /* Loop counter */ int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */ WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
int base; /* Index of the first available table cursor */ int iCur; /* VDBE Cursor number for pTab */
sqlite *db; /* Main database structure */ sqlite *db; /* Main database structure */
int isView; /* True if attempting to delete from a view */ int isView; /* True if attempting to delete from a view */
AuthContext sContext; /* Authorization context */ AuthContext sContext; /* Authorization context */
@ -119,9 +119,10 @@ void sqliteDeleteFrom(
/* Resolve the column names in all the expressions. /* Resolve the column names in all the expressions.
*/ */
base = pParse->nTab++; assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
if( pWhere ){ if( pWhere ){
if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){ if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@ -149,7 +150,7 @@ void sqliteDeleteFrom(
*/ */
if( isView ){ if( isView ){
Select *pView = sqliteSelectDup(pTab->pSelect); Select *pView = sqliteSelectDup(pTab->pSelect);
sqliteSelect(pParse, pView, SRT_TempTable, base, 0, 0, 0); sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
sqliteSelectDelete(pView); sqliteSelectDelete(pView);
} }
@ -172,13 +173,13 @@ void sqliteDeleteFrom(
int addr; int addr;
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
} }
sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2); sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2);
addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0); addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
sqliteVdbeAddOp(v, OP_Next, base, addr); sqliteVdbeAddOp(v, OP_Next, iCur, addr);
sqliteVdbeResolveLabel(v, endOfLoop); sqliteVdbeResolveLabel(v, endOfLoop);
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
} }
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb); sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
@ -194,7 +195,7 @@ void sqliteDeleteFrom(
else{ else{
/* Begin the database scan /* Begin the database scan
*/ */
pWInfo = sqliteWhereBegin(pParse, base, pTabList, pWhere, 1, 0); pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
if( pWInfo==0 ) goto delete_from_cleanup; if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted. /* Remember the key of every item to be deleted.
@ -229,15 +230,15 @@ void sqliteDeleteFrom(
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
} }
sqliteVdbeAddOp(v, OP_MoveTo, base, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
sqliteVdbeAddOp(v, OP_Recno, base, 0); sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
sqliteVdbeAddOp(v, OP_RowData, base, 0); sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0); sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
} }
sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
@ -252,9 +253,9 @@ void sqliteDeleteFrom(
** before the trigger fires. If there are no row triggers, the ** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop. ** cursors are opened only once on the outside the loop.
*/ */
pParse->nTab = base + 1; pParse->nTab = iCur + 1;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
@ -267,7 +268,7 @@ void sqliteDeleteFrom(
} }
/* Delete the row */ /* Delete the row */
sqliteGenerateRowDelete(db, v, pTab, base, pParse->trigStack==0); sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
} }
/* If there are row triggers, close all cursors then invoke /* If there are row triggers, close all cursors then invoke
@ -276,9 +277,9 @@ void sqliteDeleteFrom(
if( row_triggers_exist ){ if( row_triggers_exist ){
if( !isView ){ if( !isView ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum); sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
} }
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
} }
sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
@ -293,10 +294,10 @@ void sqliteDeleteFrom(
/* Close the cursors after the loop if there are no row triggers */ /* Close the cursors after the loop if there are no row triggers */
if( !row_triggers_exist ){ if( !row_triggers_exist ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum); sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
} }
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
pParse->nTab = base; pParse->nTab = iCur;
} }
} }
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
@ -341,13 +342,13 @@ void sqliteGenerateRowDelete(
sqlite *db, /* The database containing the index */ sqlite *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */ Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */ Table *pTab, /* Table containing the row to be deleted */
int base, /* Cursor number for the table */ int iCur, /* Cursor number for the table */
int count /* Increment the row change counter */ int count /* Increment the row change counter */
){ ){
int addr; int addr;
addr = sqliteVdbeAddOp(v, OP_NotExists, base, 0); addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
sqliteGenerateRowIndexDelete(db, v, pTab, base, 0); sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqliteVdbeAddOp(v, OP_Delete, base, count); sqliteVdbeAddOp(v, OP_Delete, iCur, count);
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
} }
@ -359,19 +360,19 @@ void sqliteGenerateRowDelete(
** These are the requirements: ** These are the requirements:
** **
** 1. A read/write cursor pointing to pTab, the table containing the row ** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "base". ** to be deleted, must be opened as cursor number "iCur".
** **
** 2. Read/write cursors for all indices of pTab must be open as ** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index. ** cursor number iCur+i for the i-th index.
** **
** 3. The "base" cursor must be pointing to the row that is to be ** 3. The "iCur" cursor must be pointing to the row that is to be
** deleted. ** deleted.
*/ */
void sqliteGenerateRowIndexDelete( void sqliteGenerateRowIndexDelete(
sqlite *db, /* The database containing the index */ sqlite *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */ Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */ Table *pTab, /* Table containing the row to be deleted */
int base, /* Cursor number for the table */ int iCur, /* Cursor number for the table */
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
){ ){
int i; int i;
@ -380,17 +381,17 @@ void sqliteGenerateRowIndexDelete(
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j; int j;
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
sqliteVdbeAddOp(v, OP_Recno, base, 0); sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
for(j=0; j<pIdx->nColumn; j++){ for(j=0; j<pIdx->nColumn; j++){
int idx = pIdx->aiColumn[j]; int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){ if( idx==pTab->iPKey ){
sqliteVdbeAddOp(v, OP_Dup, j, 0); sqliteVdbeAddOp(v, OP_Dup, j, 0);
}else{ }else{
sqliteVdbeAddOp(v, OP_Column, base, idx); sqliteVdbeAddOp(v, OP_Column, iCur, idx);
} }
} }
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0); sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
} }
} }

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite. ** for generating VDBE code that evaluates expressions in SQLite.
** **
** $Id: expr.c,v 1.94 2003/04/22 20:30:39 drh Exp $ ** $Id: expr.c,v 1.95 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -194,6 +194,7 @@ SrcList *sqliteSrcListDup(SrcList *p){
pNew->a[i].zName = sqliteStrDup(p->a[i].zName); pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias); pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
pNew->a[i].jointype = p->a[i].jointype; pNew->a[i].jointype = p->a[i].jointype;
pNew->a[i].iCursor = p->a[i].iCursor;
pNew->a[i].pTab = 0; pNew->a[i].pTab = 0;
pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect); pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn); pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn);
@ -402,13 +403,16 @@ int sqliteIsRowid(const char *z){
*/ */
int sqliteExprResolveIds( int sqliteExprResolveIds(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
int base, /* VDBE cursor number for first entry in pTabList */
SrcList *pTabList, /* List of tables used to resolve column names */ SrcList *pTabList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */ ExprList *pEList, /* List of expressions used to resolve "AS" */
Expr *pExpr /* The expression to be analyzed. */ Expr *pExpr /* The expression to be analyzed. */
){ ){
int i;
if( pExpr==0 || pTabList==0 ) return 0; if( pExpr==0 || pTabList==0 ) return 0;
assert( base+pTabList->nSrc<=pParse->nTab ); for(i=0; i<pTabList->nSrc; i++){
assert( pTabList->a[i].iCursor>=0 && pTabList->a[i].iCursor<pParse->nTab );
}
switch( pExpr->op ){ switch( pExpr->op ){
/* Double-quoted strings (ex: "abc") are used as identifiers if /* Double-quoted strings (ex: "abc") are used as identifiers if
** possible. Otherwise they remain as strings. Single-quoted ** possible. Otherwise they remain as strings. Single-quoted
@ -430,7 +434,6 @@ int sqliteExprResolveIds(
*/ */
case TK_ID: { case TK_ID: {
int cnt = 0; /* Number of matches */ int cnt = 0; /* Number of matches */
int i; /* Loop counter */
char *z; char *z;
int iDb = -1; int iDb = -1;
@ -447,7 +450,7 @@ int sqliteExprResolveIds(
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
cnt++; cnt++;
pExpr->iTable = i + base; pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb; pExpr->iDb = pTab->iDb;
if( j==pTab->iPKey ){ if( j==pTab->iPKey ){
/* Substitute the record number for the INTEGER PRIMARY KEY */ /* Substitute the record number for the INTEGER PRIMARY KEY */
@ -476,7 +479,7 @@ int sqliteExprResolveIds(
} }
if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){ if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){
pExpr->iColumn = -1; pExpr->iColumn = -1;
pExpr->iTable = base; pExpr->iTable = pTabList->a[0].iCursor;
pExpr->iDb = iDb; pExpr->iDb = iDb;
cnt = 1 + (pTabList->nSrc>1); cnt = 1 + (pTabList->nSrc>1);
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
@ -491,7 +494,7 @@ int sqliteExprResolveIds(
return 1; return 1;
} }
if( pExpr->op==TK_COLUMN ){ if( pExpr->op==TK_COLUMN ){
sqliteAuthRead(pParse, pExpr, pTabList, base); sqliteAuthRead(pParse, pExpr, pTabList);
} }
break; break;
} }
@ -550,13 +553,13 @@ int sqliteExprResolveIds(
} }
} }
if( 0==(cntTab++) ){ if( 0==(cntTab++) ){
pExpr->iTable = i + base; pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb; pExpr->iDb = pTab->iDb;
} }
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++; cnt++;
pExpr->iTable = i + base; pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb; pExpr->iDb = pTab->iDb;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->iColumn = j==pTab->iPKey ? -1 : j;
@ -620,14 +623,14 @@ int sqliteExprResolveIds(
sqliteExprDelete(pExpr->pRight); sqliteExprDelete(pExpr->pRight);
pExpr->pRight = 0; pExpr->pRight = 0;
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
sqliteAuthRead(pParse, pExpr, pTabList, base); sqliteAuthRead(pParse, pExpr, pTabList);
break; break;
} }
case TK_IN: { case TK_IN: {
Vdbe *v = sqliteGetVdbe(pParse); Vdbe *v = sqliteGetVdbe(pParse);
if( v==0 ) return 1; if( v==0 ) return 1;
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pLeft) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
return 1; return 1;
} }
if( pExpr->pSelect ){ if( pExpr->pSelect ){
@ -697,11 +700,11 @@ int sqliteExprResolveIds(
/* For all else, just recursively walk the tree */ /* For all else, just recursively walk the tree */
default: { default: {
if( pExpr->pLeft if( pExpr->pLeft
&& sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pLeft) ){ && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
return 1; return 1;
} }
if( pExpr->pRight if( pExpr->pRight
&& sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pRight) ){ && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pRight) ){
return 1; return 1;
} }
if( pExpr->pList ){ if( pExpr->pList ){
@ -709,7 +712,7 @@ int sqliteExprResolveIds(
ExprList *pList = pExpr->pList; ExprList *pList = pExpr->pList;
for(i=0; i<pList->nExpr; i++){ for(i=0; i<pList->nExpr; i++){
Expr *pArg = pList->a[i].pExpr; Expr *pArg = pList->a[i].pExpr;
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pArg) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pArg) ){
return 1; return 1;
} }
} }

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** to handle INSERT statements in SQLite.
** **
** $Id: insert.c,v 1.82 2003/04/24 01:45:04 drh Exp $ ** $Id: insert.c,v 1.83 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -98,7 +98,7 @@ void sqliteInsert(
Vdbe *v; /* Generate code into this virtual machine */ Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
int nColumn; /* Number of columns in the data */ int nColumn; /* Number of columns in the data */
int base; /* First available cursor */ int base; /* VDBE Cursor number for pTab */
int iCont, iBreak; /* Beginning and end of the loop over srcTab */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */
sqlite *db; /* The main database structure */ sqlite *db; /* The main database structure */
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
@ -245,7 +245,7 @@ void sqliteInsert(
nColumn = pList->nExpr; nColumn = pList->nExpr;
dummy.nSrc = 0; dummy.nSrc = 0;
for(i=0; i<nColumn; i++){ for(i=0; i<nColumn; i++){
if( sqliteExprResolveIds(pParse, 0, &dummy, 0, pList->a[i].pExpr) ){ if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){
goto insert_cleanup; goto insert_cleanup;
} }
if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){ if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite. ** to handle SELECT statements in SQLite.
** **
** $Id: select.c,v 1.135 2003/04/29 16:20:46 drh Exp $ ** $Id: select.c,v 1.136 2003/05/02 14:32:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -296,13 +296,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** will work correctly for both SQLite and Oracle8. ** will work correctly for both SQLite and Oracle8.
*/ */
static int sqliteOracle8JoinFixup( static int sqliteOracle8JoinFixup(
int base, /* VDBE cursor number for first table in pSrc */
SrcList *pSrc, /* List of tables being joined */ SrcList *pSrc, /* List of tables being joined */
Expr *pWhere /* The WHERE clause of the SELECT statement */ Expr *pWhere /* The WHERE clause of the SELECT statement */
){ ){
int rc = 0; int rc = 0;
if( ExprHasProperty(pWhere, EP_Oracle8Join) && pWhere->op==TK_COLUMN ){ if( ExprHasProperty(pWhere, EP_Oracle8Join) && pWhere->op==TK_COLUMN ){
int idx = pWhere->iTable - base; int idx;
for(idx=0; idx<pSrc->nSrc; idx++){
if( pSrc->a[idx].iCursor==pWhere->iTable ) break;
}
assert( idx>=0 && idx<pSrc->nSrc ); assert( idx>=0 && idx<pSrc->nSrc );
if( idx>0 ){ if( idx>0 ){
pSrc->a[idx-1].jointype &= ~JT_INNER; pSrc->a[idx-1].jointype &= ~JT_INNER;
@ -311,16 +313,16 @@ static int sqliteOracle8JoinFixup(
} }
} }
if( pWhere->pRight ){ if( pWhere->pRight ){
rc = sqliteOracle8JoinFixup(base, pSrc, pWhere->pRight); rc = sqliteOracle8JoinFixup(pSrc, pWhere->pRight);
} }
if( pWhere->pLeft ){ if( pWhere->pLeft ){
rc |= sqliteOracle8JoinFixup(base, pSrc, pWhere->pLeft); rc |= sqliteOracle8JoinFixup(pSrc, pWhere->pLeft);
} }
if( pWhere->pList ){ if( pWhere->pList ){
int i; int i;
ExprList *pList = pWhere->pList; ExprList *pList = pWhere->pList;
for(i=0; i<pList->nExpr && rc==0; i++){ for(i=0; i<pList->nExpr && rc==0; i++){
rc |= sqliteOracle8JoinFixup(base, pSrc, pList->a[i].pExpr); rc |= sqliteOracle8JoinFixup(pSrc, pList->a[i].pExpr);
} }
} }
if( rc==1 && (pWhere->op==TK_AND || pWhere->op==TK_EQ) ){ if( rc==1 && (pWhere->op==TK_AND || pWhere->op==TK_EQ) ){
@ -687,12 +689,11 @@ static void generateSortTail(
*/ */
static void generateColumnTypes( static void generateColumnTypes(
Parse *pParse, /* Parser context */ Parse *pParse, /* Parser context */
int base, /* VDBE cursor corresponding to first entry in pTabList */
SrcList *pTabList, /* List of tables */ SrcList *pTabList, /* List of tables */
ExprList *pEList /* Expressions defining the result set */ ExprList *pEList /* Expressions defining the result set */
){ ){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int i; int i, j;
if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){ if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){
return; return;
} }
@ -701,8 +702,11 @@ static void generateColumnTypes(
char *zType = 0; char *zType = 0;
if( p==0 ) continue; if( p==0 ) continue;
if( p->op==TK_COLUMN && pTabList ){ if( p->op==TK_COLUMN && pTabList ){
Table *pTab = pTabList->a[p->iTable - base].pTab; Table *pTab;
int iCol = p->iColumn; int iCol = p->iColumn;
for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
assert( j<pTabList->nSrc );
pTab = pTabList->a[j].pTab;
if( iCol<0 ) iCol = pTab->iPKey; if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){ if( iCol<0 ){
@ -729,12 +733,11 @@ static void generateColumnTypes(
*/ */
static void generateColumnNames( static void generateColumnNames(
Parse *pParse, /* Parser context */ Parse *pParse, /* Parser context */
int base, /* VDBE cursor corresponding to first entry in pTabList */
SrcList *pTabList, /* List of tables */ SrcList *pTabList, /* List of tables */
ExprList *pEList /* Expressions defining the result set */ ExprList *pEList /* Expressions defining the result set */
){ ){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int i; int i, j;
if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return; if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
pParse->colNamesSet = 1; pParse->colNamesSet = 1;
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
@ -751,9 +754,12 @@ static void generateColumnNames(
} }
showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0; showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0;
if( p->op==TK_COLUMN && pTabList ){ if( p->op==TK_COLUMN && pTabList ){
Table *pTab = pTabList->a[p->iTable - base].pTab; Table *pTab;
char *zCol; char *zCol;
int iCol = p->iColumn; int iCol = p->iColumn;
for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
assert( j<pTabList->nSrc );
pTab = pTabList->a[j].pTab;
if( iCol<0 ) iCol = pTab->iPKey; if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){ if( iCol<0 ){
@ -771,7 +777,7 @@ static void generateColumnNames(
char *zName = 0; char *zName = 0;
char *zTab; char *zTab;
zTab = pTabList->a[p->iTable - base].zAlias; zTab = pTabList->a[j].zAlias;
if( showFullNames || zTab==0 ) zTab = pTab->zName; if( showFullNames || zTab==0 ) zTab = pTab->zName;
sqliteSetString(&zName, zTab, ".", zCol, 0); sqliteSetString(&zName, zTab, ".", zCol, 0);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
@ -1368,8 +1374,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
int iCont, iBreak, iStart; int iCont, iBreak, iStart;
assert( p->pEList ); assert( p->pEList );
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
generateColumnNames(pParse, p->base, 0, p->pEList); generateColumnNames(pParse, 0, p->pEList);
generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); generateColumnTypes(pParse, p->pSrc, p->pEList);
} }
iBreak = sqliteVdbeMakeLabel(v); iBreak = sqliteVdbeMakeLabel(v);
iCont = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v);
@ -1425,8 +1431,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
*/ */
assert( p->pEList ); assert( p->pEList );
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
generateColumnNames(pParse, p->base, 0, p->pEList); generateColumnNames(pParse, 0, p->pEList);
generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); generateColumnTypes(pParse, p->pSrc, p->pEList);
} }
iBreak = sqliteVdbeMakeLabel(v); iBreak = sqliteVdbeMakeLabel(v);
iCont = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v);
@ -1466,37 +1472,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
return 0; return 0;
} }
/*
** Recursively scan through an expression tree. For every reference
** to a column in table number iFrom, change that reference to the
** same column in table number iTo.
*/
static void changeTablesInList(ExprList*, int, int); /* Forward Declaration */
static void changeTables(Expr *pExpr, int iFrom, int iTo){
if( pExpr==0 ) return;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iFrom ){
pExpr->iTable = iTo;
}else{
changeTables(pExpr->pLeft, iFrom, iTo);
changeTables(pExpr->pRight, iFrom, iTo);
changeTablesInList(pExpr->pList, iFrom, iTo);
}
}
static void changeTablesInList(ExprList *pList, int iFrom, int iTo){
if( pList ){
int i;
for(i=0; i<pList->nExpr; i++){
changeTables(pList->a[i].pExpr, iFrom, iTo);
}
}
}
/* /*
** Scan through the expression pExpr. Replace every reference to ** Scan through the expression pExpr. Replace every reference to
** a column in table number iTable with a copy of the corresponding ** a column in table number iTable with a copy of the iColumn-th
** entry in pEList. (But leave references to the ROWID column ** entry in pEList. (But leave references to the ROWID column
** unchanged.) When making a copy of an expression in pEList, change ** unchanged.)
** references to columns in table iSub into references to table iTable.
** **
** This routine is part of the flattening procedure. A subquery ** This routine is part of the flattening procedure. A subquery
** whose result set is defined by pEList appears as entry in the ** whose result set is defined by pEList appears as entry in the
@ -1505,8 +1485,8 @@ static void changeTablesInList(ExprList *pList, int iFrom, int iTo){
** changes to pExpr so that it refers directly to the source table ** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery. ** of the subquery rather the result set of the subquery.
*/ */
static void substExprList(ExprList*,int,ExprList*,int); /* Forward Decl */ static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
if( pExpr==0 ) return; if( pExpr==0 ) return;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){ if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
Expr *pNew; Expr *pNew;
@ -1527,21 +1507,18 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){
pExpr->iAgg = pNew->iAgg; pExpr->iAgg = pNew->iAgg;
sqliteTokenCopy(&pExpr->token, &pNew->token); sqliteTokenCopy(&pExpr->token, &pNew->token);
sqliteTokenCopy(&pExpr->span, &pNew->span); sqliteTokenCopy(&pExpr->span, &pNew->span);
if( iSub!=iTable ){
changeTables(pExpr, iSub, iTable);
}
}else{ }else{
substExpr(pExpr->pLeft, iTable, pEList, iSub); substExpr(pExpr->pLeft, iTable, pEList);
substExpr(pExpr->pRight, iTable, pEList, iSub); substExpr(pExpr->pRight, iTable, pEList);
substExprList(pExpr->pList, iTable, pEList, iSub); substExprList(pExpr->pList, iTable, pEList);
} }
} }
static void static void
substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){ substExprList(ExprList *pList, int iTable, ExprList *pEList){
int i; int i;
if( pList==0 ) return; if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){ for(i=0; i<pList->nExpr; i++){
substExpr(pList->a[i].pExpr, iTable, pEList, iSub); substExpr(pList->a[i].pExpr, iTable, pEList);
} }
} }
@ -1621,8 +1598,8 @@ static int flattenSubquery(
SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSrc; /* The FROM clause of the outer query */
SrcList *pSubSrc; /* The FROM clause of the subquery */ SrcList *pSubSrc; /* The FROM clause of the subquery */
ExprList *pList; /* The result set of the outer query */ ExprList *pList; /* The result set of the outer query */
int iParent; /* VDBE cursor number of the pSub result set temp table */
int i; int i;
int iParent, iSub;
Expr *pWhere; Expr *pWhere;
/* Check to see if flattening is permitted. Return 0 if not. /* Check to see if flattening is permitted. Return 0 if not.
@ -1646,9 +1623,9 @@ static int flattenSubquery(
/* If we reach this point, it means flattening is permitted for the /* If we reach this point, it means flattening is permitted for the
** iFrom-th entry of the FROM clause in the outer query. ** iFrom-th entry of the FROM clause in the outer query.
*/ */
iParent = p->base + iFrom; iParent = pSrc->a[iFrom].iCursor;
iSub = pSub->base; pSrc->a[iFrom].iCursor = pSubSrc->a[0].iCursor;
substExprList(p->pEList, iParent, pSub->pEList, iSub); substExprList(p->pEList, iParent, pSub->pEList);
pList = p->pEList; pList = p->pEList;
for(i=0; i<pList->nExpr; i++){ for(i=0; i<pList->nExpr; i++){
Expr *pExpr; Expr *pExpr;
@ -1657,22 +1634,18 @@ static int flattenSubquery(
} }
} }
if( isAgg ){ if( isAgg ){
substExprList(p->pGroupBy, iParent, pSub->pEList, iSub); substExprList(p->pGroupBy, iParent, pSub->pEList);
substExpr(p->pHaving, iParent, pSub->pEList, iSub); substExpr(p->pHaving, iParent, pSub->pEList);
} }
if( pSub->pOrderBy ){ if( pSub->pOrderBy ){
assert( p->pOrderBy==0 ); assert( p->pOrderBy==0 );
p->pOrderBy = pSub->pOrderBy; p->pOrderBy = pSub->pOrderBy;
pSub->pOrderBy = 0; pSub->pOrderBy = 0;
changeTablesInList(p->pOrderBy, iSub, iParent);
}else if( p->pOrderBy ){ }else if( p->pOrderBy ){
substExprList(p->pOrderBy, iParent, pSub->pEList, iSub); substExprList(p->pOrderBy, iParent, pSub->pEList);
} }
if( pSub->pWhere ){ if( pSub->pWhere ){
pWhere = sqliteExprDup(pSub->pWhere); pWhere = sqliteExprDup(pSub->pWhere);
if( iParent!=iSub ){
changeTables(pWhere, iSub, iParent);
}
}else{ }else{
pWhere = 0; pWhere = 0;
} }
@ -1680,12 +1653,9 @@ static int flattenSubquery(
assert( p->pHaving==0 ); assert( p->pHaving==0 );
p->pHaving = p->pWhere; p->pHaving = p->pWhere;
p->pWhere = pWhere; p->pWhere = pWhere;
substExpr(p->pHaving, iParent, pSub->pEList, iSub); substExpr(p->pHaving, iParent, pSub->pEList);
if( pSub->pHaving ){ if( pSub->pHaving ){
Expr *pHaving = sqliteExprDup(pSub->pHaving); Expr *pHaving = sqliteExprDup(pSub->pHaving);
if( iParent!=iSub ){
changeTables(pHaving, iSub, iParent);
}
if( p->pHaving ){ if( p->pHaving ){
p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0); p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0);
}else{ }else{
@ -1694,13 +1664,10 @@ static int flattenSubquery(
} }
assert( p->pGroupBy==0 ); assert( p->pGroupBy==0 );
p->pGroupBy = sqliteExprListDup(pSub->pGroupBy); p->pGroupBy = sqliteExprListDup(pSub->pGroupBy);
if( iParent!=iSub ){
changeTablesInList(p->pGroupBy, iSub, iParent);
}
}else if( p->pWhere==0 ){ }else if( p->pWhere==0 ){
p->pWhere = pWhere; p->pWhere = pWhere;
}else{ }else{
substExpr(p->pWhere, iParent, pSub->pEList, iSub); substExpr(p->pWhere, iParent, pSub->pEList);
if( pWhere ){ if( pWhere ){
p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0); p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
} }
@ -1716,19 +1683,6 @@ static int flattenSubquery(
} }
p->nOffset += pSub->nOffset; p->nOffset += pSub->nOffset;
/* If the subquery contains subqueries of its own, that were not
** flattened, then code will have already been generated to put
** the results of those sub-subqueries into VDBE cursors relative
** to the subquery. We must translate the cursor number into values
** suitable for use by the outer query.
*/
for(i=0; i<pSubSrc->nSrc; i++){
Vdbe *v;
if( pSubSrc->a[i].pSelect==0 ) continue;
v = sqliteGetVdbe(pParse);
sqliteVdbeAddOp(v, OP_RenameCursor, pSub->base+i, p->base+i);
}
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
sqliteDeleteTable(0, pSrc->a[iFrom].pTab); sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
} }
@ -1817,8 +1771,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) return 0; if( v==0 ) return 0;
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
generateColumnNames(pParse, p->base, p->pSrc, p->pEList); generateColumnNames(pParse, p->pSrc, p->pEList);
generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); generateColumnTypes(pParse, p->pSrc, p->pEList);
} }
/* Generating code to find the min or the max. Basically all we have /* Generating code to find the min or the max. Basically all we have
@ -1829,7 +1783,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){ if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteCodeVerifySchema(pParse); sqliteCodeVerifySchema(pParse);
} }
base = p->base; base = p->pSrc->a[0].iCursor;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@ -1928,7 +1882,6 @@ int sqliteSelect(
Expr *pHaving; /* The HAVING clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */
int isDistinct; /* True if the DISTINCT keyword is present */ int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */ int distinct; /* Table to use for the distinct set */
int base; /* First cursor available for use */
int rc = 1; /* Value to return from this function */ int rc = 1; /* Value to return from this function */
if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1; if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1;
@ -1949,12 +1902,9 @@ int sqliteSelect(
pHaving = p->pHaving; pHaving = p->pHaving;
isDistinct = p->isDistinct; isDistinct = p->isDistinct;
/* Allocate a block of VDBE cursors, one for each table in the FROM clause. /* Allocate VDBE cursors for each table in the FROM clause
** The WHERE processing requires that the cursors for the tables in the
** FROM clause be consecutive.
*/ */
base = p->base = pParse->nTab; sqliteSrcListAssignCursors(pParse, pTabList);
pParse->nTab += pTabList->nSrc;
/* /*
** Do not even attempt to generate any code if we have already seen ** Do not even attempt to generate any code if we have already seen
@ -2000,7 +1950,7 @@ int sqliteSelect(
** Resolve the column names and do a semantics check on all the expressions. ** Resolve the column names and do a semantics check on all the expressions.
*/ */
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
if( sqliteExprResolveIds(pParse, base, pTabList, 0, pEList->a[i].pExpr) ){ if( sqliteExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){
goto select_end; goto select_end;
} }
if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){ if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){
@ -2008,20 +1958,20 @@ int sqliteSelect(
} }
} }
if( pWhere ){ if( pWhere ){
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pWhere) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){
goto select_end; goto select_end;
} }
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
goto select_end; goto select_end;
} }
sqliteOracle8JoinFixup(base, pTabList, pWhere); sqliteOracle8JoinFixup(pTabList, pWhere);
} }
if( pHaving ){ if( pHaving ){
if( pGroupBy==0 ){ if( pGroupBy==0 ){
sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
goto select_end; goto select_end;
} }
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pHaving) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){
goto select_end; goto select_end;
} }
if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){ if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){
@ -2036,7 +1986,7 @@ int sqliteSelect(
sqliteExprDelete(pE); sqliteExprDelete(pE);
pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
} }
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
goto select_end; goto select_end;
} }
if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@ -2064,7 +2014,7 @@ int sqliteSelect(
sqliteExprDelete(pE); sqliteExprDelete(pE);
pE = pGroupBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); pE = pGroupBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
} }
if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
goto select_end; goto select_end;
} }
if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@ -2102,7 +2052,7 @@ int sqliteSelect(
** step is skipped if the output is going to some other destination. ** step is skipped if the output is going to some other destination.
*/ */
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
generateColumnNames(pParse, p->base, pTabList, pEList); generateColumnNames(pParse, pTabList, pEList);
} }
/* Set the limiter /* Set the limiter
@ -2134,8 +2084,8 @@ int sqliteSelect(
zSavedAuthContext = pParse->zAuthContext; zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pTabList->a[i].zName; pParse->zAuthContext = pTabList->a[i].zName;
} }
sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i, sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable,
p, i, &isAgg); pTabList->a[i].iCursor, p, i, &isAgg);
if( pTabList->a[i].zName!=0 ){ if( pTabList->a[i].zName!=0 ){
pParse->zAuthContext = zSavedAuthContext; pParse->zAuthContext = zSavedAuthContext;
} }
@ -2163,7 +2113,7 @@ int sqliteSelect(
** than a callback. ** than a callback.
*/ */
if( eDest==SRT_Callback ){ if( eDest==SRT_Callback ){
generateColumnTypes(pParse, p->base, pTabList, pEList); generateColumnTypes(pParse, pTabList, pEList);
} }
/* If the output is destined for a temporary table, open that table. /* If the output is destined for a temporary table, open that table.
@ -2237,7 +2187,7 @@ int sqliteSelect(
/* Begin the database scan /* Begin the database scan
*/ */
pWInfo = sqliteWhereBegin(pParse, p->base, pTabList, pWhere, 0, pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0,
pGroupBy ? 0 : &pOrderBy); pGroupBy ? 0 : &pOrderBy);
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.182 2003/04/29 16:20:46 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.183 2003/05/02 14:32:14 drh Exp $
*/ */
#include "config.h" #include "config.h"
#include "sqlite.h" #include "sqlite.h"
@ -717,7 +717,6 @@ struct WhereInfo {
SrcList *pTabList; /* List of tables in the join */ SrcList *pTabList; /* List of tables in the join */
int iContinue; /* Jump here to continue with next record */ int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */ int iBreak; /* Jump here to break out of the loop */
int base; /* Index of first Open opcode */
int nLevel; /* Number of nested loop */ int nLevel; /* Number of nested loop */
int savedNTab; /* Value of pParse->nTab before WhereBegin() */ int savedNTab; /* Value of pParse->nTab before WhereBegin() */
int peakNTab; /* Value of pParse->nTab after WhereBegin() */ int peakNTab; /* Value of pParse->nTab after WhereBegin() */
@ -754,7 +753,6 @@ struct Select {
Select *pPrior; /* Prior select in a compound select statement */ Select *pPrior; /* Prior select in a compound select statement */
int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */ int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */
char *zSelect; /* Complete text of the SELECT command */ char *zSelect; /* Complete text of the SELECT command */
int base; /* Index of VDBE cursor for left-most FROM table */
}; };
/* /*
@ -1039,6 +1037,7 @@ IdList *sqliteIdListAppend(IdList*, Token*);
int sqliteIdListIndex(IdList*,const char*); int sqliteIdListIndex(IdList*,const char*);
SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*); SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
void sqliteSrcListAddAlias(SrcList*, Token*); void sqliteSrcListAddAlias(SrcList*, Token*);
void sqliteSrcListAssignCursors(Parse*, SrcList*);
void sqliteIdListDelete(IdList*); void sqliteIdListDelete(IdList*);
void sqliteSrcListDelete(SrcList*); void sqliteSrcListDelete(SrcList*);
void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,int,Token*,Token*); void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,int,Token*,Token*);
@ -1054,7 +1053,7 @@ Table *sqliteSrcListLookup(Parse*, SrcList*);
int sqliteIsReadOnly(Parse*, Table*, int); int sqliteIsReadOnly(Parse*, Table*, int);
void sqliteDeleteFrom(Parse*, SrcList*, Expr*); void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int); void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**); WhereInfo *sqliteWhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
void sqliteWhereEnd(WhereInfo*); void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*); void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int, int); void sqliteExprIfTrue(Parse*, Expr*, int, int);
@ -1072,7 +1071,7 @@ int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteExprType(Expr*); int sqliteExprType(Expr*);
int sqliteExprCompare(Expr*, Expr*); int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*); int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, int, SrcList*, ExprList*, Expr*); int sqliteExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*); int sqliteExprAnalyzeAggregates(Parse*, Expr*);
Vdbe *sqliteGetVdbe(Parse*); Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void); int sqliteRandomByte(void);
@ -1120,12 +1119,12 @@ int sqliteJoinType(Parse*, Token*, Token*, Token*);
void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int); void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int);
void sqliteDeferForeignKey(Parse*, int); void sqliteDeferForeignKey(Parse*, int);
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
void sqliteAuthRead(Parse*,Expr*,SrcList*,int); void sqliteAuthRead(Parse*,Expr*,SrcList*);
int sqliteAuthCheck(Parse*,int, const char*, const char*, const char*); int sqliteAuthCheck(Parse*,int, const char*, const char*, const char*);
void sqliteAuthContextPush(Parse*, AuthContext*, const char*); void sqliteAuthContextPush(Parse*, AuthContext*, const char*);
void sqliteAuthContextPop(AuthContext*); void sqliteAuthContextPop(AuthContext*);
#else #else
# define sqliteAuthRead(a,b,c,d) # define sqliteAuthRead(a,b,c)
# define sqliteAuthCheck(a,b,c,d) SQLITE_OK # define sqliteAuthCheck(a,b,c,d) SQLITE_OK
# define sqliteAuthContextPush(a,b,c) # define sqliteAuthContextPush(a,b,c)
# define sqliteAuthContextPop(a) # define sqliteAuthContextPop(a)

View File

@ -678,7 +678,7 @@ int sqliteCodeRowTrigger(
/* code the WHEN clause */ /* code the WHEN clause */
endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
whenExpr = sqliteExprDup(pTrigger->pWhen); whenExpr = sqliteExprDup(pTrigger->pWhen);
if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
pParse->trigStack = pParse->trigStack->pNext; pParse->trigStack = pParse->trigStack->pNext;
sqliteFree(pTriggerStack); sqliteFree(pTriggerStack);
sqliteExprDelete(whenExpr); sqliteExprDelete(whenExpr);

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.64 2003/04/25 17:52:11 drh Exp $ ** $Id: update.c,v 1.65 2003/05/02 14:32:14 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -38,7 +38,7 @@ void sqliteUpdate(
Index *pIdx; /* For looping over indices */ Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */ int nIdx; /* Number of indices that need updating */
int nIdxTotal; /* Total number of indices */ int nIdxTotal; /* Total number of indices */
int base; /* Index of first available table cursor */ int iCur; /* VDBE Cursor number of pTab */
sqlite *db; /* The database structure */ sqlite *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */ Index **apIdx = 0; /* An array of indices that need updating too */
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */ char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
@ -98,7 +98,7 @@ void sqliteUpdate(
** need to occur right after the database cursor. So go ahead and ** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case. ** allocate enough space, just in case.
*/ */
base = pParse->nTab++; pTabList->a[0].iCursor = iCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++; pParse->nTab++;
} }
@ -111,7 +111,7 @@ void sqliteUpdate(
*/ */
chngRecno = 0; chngRecno = 0;
for(i=0; i<pChanges->nExpr; i++){ for(i=0; i<pChanges->nExpr; i++){
if( sqliteExprResolveIds(pParse, base, pTabList, 0, pChanges->a[i].pExpr) ){ if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
goto update_cleanup; goto update_cleanup;
} }
if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
@ -185,7 +185,7 @@ void sqliteUpdate(
** WHERE clause. ** WHERE clause.
*/ */
if( pWhere ){ if( pWhere ){
if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){ if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
goto update_cleanup; goto update_cleanup;
} }
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@ -211,13 +211,13 @@ void sqliteUpdate(
if( isView ){ if( isView ){
Select *pView; Select *pView;
pView = sqliteSelectDup(pTab->pSelect); pView = sqliteSelectDup(pTab->pSelect);
sqliteSelect(pParse, pView, SRT_TempTable, base, 0, 0, 0); sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
sqliteSelectDelete(pView); sqliteSelectDelete(pView);
} }
/* Begin the database scan /* Begin the database scan
*/ */
pWInfo = sqliteWhereBegin(pParse, base, pTabList, pWhere, 1, 0); pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated. /* Remember the index of every item to be updated.
@ -252,14 +252,14 @@ void sqliteUpdate(
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
} }
sqliteVdbeAddOp(v, OP_MoveTo, base, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
/* Generate the OLD table /* Generate the OLD table
*/ */
sqliteVdbeAddOp(v, OP_Recno, base, 0); sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
sqliteVdbeAddOp(v, OP_RowData, base, 0); sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0); sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
/* Generate the NEW table /* Generate the NEW table
@ -267,7 +267,7 @@ void sqliteUpdate(
if( chngRecno ){ if( chngRecno ){
sqliteExprCode(pParse, pRecnoExpr); sqliteExprCode(pParse, pRecnoExpr);
}else{ }else{
sqliteVdbeAddOp(v, OP_Recno, base, 0); sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
} }
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){ if( i==pTab->iPKey ){
@ -276,7 +276,7 @@ void sqliteUpdate(
} }
j = aXRef[i]; j = aXRef[i];
if( j<0 ){ if( j<0 ){
sqliteVdbeAddOp(v, OP_Column, base, i); sqliteVdbeAddOp(v, OP_Column, iCur, i);
}else{ }else{
sqliteExprCode(pParse, pChanges->a[j].pExpr); sqliteExprCode(pParse, pChanges->a[j].pExpr);
} }
@ -284,7 +284,7 @@ void sqliteUpdate(
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
} }
/* Fire the BEFORE and INSTEAD OF triggers /* Fire the BEFORE and INSTEAD OF triggers
@ -303,7 +303,7 @@ void sqliteUpdate(
** to be deleting some records. ** to be deleting some records.
*/ */
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
if( onError==OE_Replace ){ if( onError==OE_Replace ){
openAll = 1; openAll = 1;
}else{ }else{
@ -318,8 +318,8 @@ void sqliteUpdate(
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){ if( openAll || aIdxUsed[i] ){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
assert( pParse->nTab>base+i+1 ); assert( pParse->nTab>iCur+i+1 );
} }
} }
@ -334,7 +334,7 @@ void sqliteUpdate(
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
} }
sqliteVdbeAddOp(v, OP_NotExists, base, addr); sqliteVdbeAddOp(v, OP_NotExists, iCur, addr);
/* If the record number will change, push the record number as it /* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently ** will be after the update. (The old record number is currently
@ -354,7 +354,7 @@ void sqliteUpdate(
} }
j = aXRef[i]; j = aXRef[i];
if( j<0 ){ if( j<0 ){
sqliteVdbeAddOp(v, OP_Column, base, i); sqliteVdbeAddOp(v, OP_Column, iCur, i);
}else{ }else{
sqliteExprCode(pParse, pChanges->a[j].pExpr); sqliteExprCode(pParse, pChanges->a[j].pExpr);
} }
@ -362,22 +362,22 @@ void sqliteUpdate(
/* Do constraint checks /* Do constraint checks
*/ */
sqliteGenerateConstraintChecks(pParse, pTab, base, aIdxUsed, chngRecno, 1, sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
onError, addr); onError, addr);
/* Delete the old indices for the current record. /* Delete the old indices for the current record.
*/ */
sqliteGenerateRowIndexDelete(db, v, pTab, base, aIdxUsed); sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
/* If changing the record number, delete the old record. /* If changing the record number, delete the old record.
*/ */
if( chngRecno ){ if( chngRecno ){
sqliteVdbeAddOp(v, OP_Delete, base, 0); sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
} }
/* Create the new index entries and the new record. /* Create the new index entries and the new record.
*/ */
sqliteCompleteInsertion(pParse, pTab, base, aIdxUsed, chngRecno, 1, -1); sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
} }
/* Increment the row counter /* Increment the row counter
@ -393,10 +393,10 @@ void sqliteUpdate(
if( !isView ){ if( !isView ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ) if( openAll || aIdxUsed[i] )
sqliteVdbeAddOp(v, OP_Close, base+i+1, 0); sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
} }
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
pParse->nTab = base; pParse->nTab = iCur;
} }
if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){ newIdx, oldIdx, onError, addr) ){
@ -415,11 +415,11 @@ void sqliteUpdate(
if( !row_triggers_exist ){ if( !row_triggers_exist ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){ if( openAll || aIdxUsed[i] ){
sqliteVdbeAddOp(v, OP_Close, base+i+1, 0); sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
} }
} }
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, iCur, 0);
pParse->nTab = base; pParse->nTab = iCur;
}else{ }else{
sqliteVdbeAddOp(v, OP_Close, newIdx, 0); sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
sqliteVdbeAddOp(v, OP_Close, oldIdx, 0); sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);

View File

@ -36,7 +36,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.220 2003/04/25 15:37:58 drh Exp $ ** $Id: vdbe.c,v 1.221 2003/05/02 14:32:14 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -3520,27 +3520,6 @@ case OP_OpenPseudo: {
break; break;
} }
/*
** Opcode: RenameCursor P1 P2 *
**
** Rename cursor number P1 as cursor number P2. If P2 was previously
** opened is is closed before the renaming occurs.
*/
case OP_RenameCursor: {
int from = pOp->p1;
int to = pOp->p2;
VERIFY( if( from<0 || to<0 ) goto bad_instruction; )
if( to<p->nCursor && p->aCsr[to].pCursor ){
cleanupCursor(&p->aCsr[to]);
}
expandCursorArraySize(p, to);
if( from<p->nCursor ){
memcpy(&p->aCsr[to], &p->aCsr[from], sizeof(p->aCsr[0]));
memset(&p->aCsr[from], 0, sizeof(p->aCsr[0]));
}
break;
}
/* Opcode: Close P1 * * /* Opcode: Close P1 * *
** **
** Close a cursor previously opened as P1. If P1 is not ** Close a cursor previously opened as P1. If P1 is not

View File

@ -12,7 +12,7 @@
** This module contains C code that generates VDBE code used to process ** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements. ** the WHERE clause of SQL statements.
** **
** $Id: where.c,v 1.77 2003/04/24 01:45:05 drh Exp $ ** $Id: where.c,v 1.78 2003/05/02 14:32:14 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -36,6 +36,21 @@ struct ExprInfo {
unsigned prereqAll; /* Bitmask of tables referenced by p */ unsigned prereqAll; /* Bitmask of tables referenced by p */
}; };
/*
** An instance of the following structure keeps track of a mapping
** between VDBE cursor numbers and bitmasks. The VDBE cursor numbers
** are small integers contained in SrcList_item.iCursor and Expr.iTable
** fields. For any given WHERE clause, we want to track which cursors
** are being used, so we assign a single bit in a 32-bit word to track
** that cursor. Then a 32-bit integer is able to show the set of all
** cursors being used.
*/
typedef struct ExprMaskSet ExprMaskSet;
struct ExprMaskSet {
int n; /* Number of assigned cursor values */
int ix[32]; /* Cursor assigned to each bit */
};
/* /*
** Determine the number of elements in an array. ** Determine the number of elements in an array.
*/ */
@ -67,37 +82,61 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
return cnt; return cnt;
} }
/*
** Initialize an expression mask set
*/
#define initMaskSet(P) memset(P, 0, sizeof(*P))
/*
** Return the bitmask for the given cursor. Assign a new bitmask
** if this is the first time the cursor has been seen.
*/
static int getMask(ExprMaskSet *pMaskSet, int iCursor){
int i;
for(i=0; i<pMaskSet->n; i++){
if( pMaskSet->ix[i]==iCursor ) return 1<<i;
}
if( i==pMaskSet->n && i<ARRAYSIZE(pMaskSet->ix) ){
pMaskSet->n++;
pMaskSet->ix[i] = iCursor;
return 1<<i;
}
return 0;
}
/*
** Destroy an expression mask set
*/
#define freeMaskSet(P) /* NO-OP */
/* /*
** This routine walks (recursively) an expression tree and generates ** This routine walks (recursively) an expression tree and generates
** a bitmask indicating which tables are used in that expression ** a bitmask indicating which tables are used in that expression
** tree. Bit 0 of the mask is set if table base+0 is used. Bit 1 ** tree.
** is set if table base+1 is used. And so forth.
** **
** In order for this routine to work, the calling function must have ** In order for this routine to work, the calling function must have
** previously invoked sqliteExprResolveIds() on the expression. See ** previously invoked sqliteExprResolveIds() on the expression. See
** the header comment on that routine for additional information. ** the header comment on that routine for additional information.
** ** The sqliteExprResolveIds() routines looks for column names and
** "base" is the cursor number (the value of the iTable field) that ** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
** corresponds to the first entry in the list of tables that appear ** the VDBE cursor number of the table.
** in the FROM clause of a SELECT. For UPDATE and DELETE statements
** there is just a single table with "base" as the cursor number.
*/ */
static int exprTableUsage(int base, Expr *p){ static int exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
unsigned int mask = 0; unsigned int mask = 0;
if( p==0 ) return 0; if( p==0 ) return 0;
if( p->op==TK_COLUMN ){ if( p->op==TK_COLUMN ){
return 1<< (p->iTable - base); return getMask(pMaskSet, p->iTable);
} }
if( p->pRight ){ if( p->pRight ){
mask = exprTableUsage(base, p->pRight); mask = exprTableUsage(pMaskSet, p->pRight);
} }
if( p->pLeft ){ if( p->pLeft ){
mask |= exprTableUsage(base, p->pLeft); mask |= exprTableUsage(pMaskSet, p->pLeft);
} }
if( p->pList ){ if( p->pList ){
int i; int i;
for(i=0; i<p->pList->nExpr; i++){ for(i=0; i<p->pList->nExpr; i++){
mask |= exprTableUsage(base, p->pList->a[i].pExpr); mask |= exprTableUsage(pMaskSet, p->pList->a[i].pExpr);
} }
} }
return mask; return mask;
@ -127,25 +166,22 @@ static int allowedOp(int op){
** "p" field filled in. The job of this routine is to analyze the ** "p" field filled in. The job of this routine is to analyze the
** subexpression and populate all the other fields of the ExprInfo ** subexpression and populate all the other fields of the ExprInfo
** structure. ** structure.
**
** "base" is the cursor number (the value of the iTable field) that
** corresponds to the first entry in the table list.
*/ */
static void exprAnalyze(int base, ExprInfo *pInfo){ static void exprAnalyze(ExprMaskSet *pMaskSet, ExprInfo *pInfo){
Expr *pExpr = pInfo->p; Expr *pExpr = pInfo->p;
pInfo->prereqLeft = exprTableUsage(base, pExpr->pLeft); pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
pInfo->prereqRight = exprTableUsage(base, pExpr->pRight); pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
pInfo->prereqAll = exprTableUsage(base, pExpr); pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
pInfo->indexable = 0; pInfo->indexable = 0;
pInfo->idxLeft = -1; pInfo->idxLeft = -1;
pInfo->idxRight = -1; pInfo->idxRight = -1;
if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){ if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){ if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
pInfo->idxRight = pExpr->pRight->iTable - base; pInfo->idxRight = pExpr->pRight->iTable;
pInfo->indexable = 1; pInfo->indexable = 1;
} }
if( pExpr->pLeft->op==TK_COLUMN ){ if( pExpr->pLeft->op==TK_COLUMN ){
pInfo->idxLeft = pExpr->pLeft->iTable - base; pInfo->idxLeft = pExpr->pLeft->iTable;
pInfo->indexable = 1; pInfo->indexable = 1;
} }
} }
@ -262,9 +298,9 @@ static Index *findSortingIndex(
** end / ** end /
** **
** There are Btree cursors associated with each table. t1 uses cursor ** There are Btree cursors associated with each table. t1 uses cursor
** "base". t2 uses cursor "base+1". And so forth. This routine generates ** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor.
** the code to open those cursors. sqliteWhereEnd() generates the code ** And so forth. This routine generates code to open those VDBE cursors
** to close them. ** and sqliteWhereEnd() generates the code to close them.
** **
** If the WHERE clause is empty, the foreach loops must each scan their ** If the WHERE clause is empty, the foreach loops must each scan their
** entire tables. Thus a three-way join is an O(N^3) operation. But if ** entire tables. Thus a three-way join is an O(N^3) operation. But if
@ -314,7 +350,6 @@ static Index *findSortingIndex(
*/ */
WhereInfo *sqliteWhereBegin( WhereInfo *sqliteWhereBegin(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
int base, /* VDBE cursor index for left-most table in pTabList */
SrcList *pTabList, /* A list of all tables to be scanned */ SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */ Expr *pWhere, /* The WHERE clause */
int pushKey, /* If TRUE, leave the table key on the stack */ int pushKey, /* If TRUE, leave the table key on the stack */
@ -327,6 +362,7 @@ WhereInfo *sqliteWhereBegin(
int nExpr; /* Number of subexpressions in the WHERE clause */ int nExpr; /* Number of subexpressions in the WHERE clause */
int loopMask; /* One bit set for each outer loop */ int loopMask; /* One bit set for each outer loop */
int haveKey; /* True if KEY is on the stack */ int haveKey; /* True if KEY is on the stack */
ExprMaskSet maskSet; /* The expression mask set */
int iDirectEq[32]; /* Term of the form ROWID==X for the N-th table */ int iDirectEq[32]; /* Term of the form ROWID==X for the N-th table */
int iDirectLt[32]; /* Term of the form ROWID<X or ROWID<=X */ int iDirectLt[32]; /* Term of the form ROWID<X or ROWID<=X */
int iDirectGt[32]; /* Term of the form ROWID>X or ROWID>=X */ int iDirectGt[32]; /* Term of the form ROWID>X or ROWID>=X */
@ -342,6 +378,7 @@ WhereInfo *sqliteWhereBegin(
** array fills up, the last entry might point to an expression which ** array fills up, the last entry might point to an expression which
** contains additional unfactored AND operators. ** contains additional unfactored AND operators.
*/ */
initMaskSet(&maskSet);
memset(aExpr, 0, sizeof(aExpr)); memset(aExpr, 0, sizeof(aExpr));
nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere); nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
if( nExpr==ARRAYSIZE(aExpr) ){ if( nExpr==ARRAYSIZE(aExpr) ){
@ -363,7 +400,6 @@ WhereInfo *sqliteWhereBegin(
} }
pWInfo->pParse = pParse; pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList; pWInfo->pTabList = pTabList;
pWInfo->base = base;
pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab; pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab;
pWInfo->iBreak = sqliteVdbeMakeLabel(v); pWInfo->iBreak = sqliteVdbeMakeLabel(v);
@ -378,7 +414,7 @@ WhereInfo *sqliteWhereBegin(
/* Analyze all of the subexpressions. /* Analyze all of the subexpressions.
*/ */
for(i=0; i<nExpr; i++){ for(i=0; i<nExpr; i++){
exprAnalyze(base, &aExpr[i]); exprAnalyze(&maskSet, &aExpr[i]);
/* If we are executing a trigger body, remove all references to /* If we are executing a trigger body, remove all references to
** new.* and old.* tables from the prerequisite masks. ** new.* and old.* tables from the prerequisite masks.
@ -386,13 +422,13 @@ WhereInfo *sqliteWhereBegin(
if( pParse->trigStack ){ if( pParse->trigStack ){
int x; int x;
if( (x = pParse->trigStack->newIdx) >= 0 ){ if( (x = pParse->trigStack->newIdx) >= 0 ){
int mask = ~(1 << (x - base)); int mask = ~getMask(&maskSet, x);
aExpr[i].prereqRight &= mask; aExpr[i].prereqRight &= mask;
aExpr[i].prereqLeft &= mask; aExpr[i].prereqLeft &= mask;
aExpr[i].prereqAll &= mask; aExpr[i].prereqAll &= mask;
} }
if( (x = pParse->trigStack->oldIdx) >= 0 ){ if( (x = pParse->trigStack->oldIdx) >= 0 ){
int mask = ~(1 << (x - base)); int mask = ~getMask(&maskSet, x);
aExpr[i].prereqRight &= mask; aExpr[i].prereqRight &= mask;
aExpr[i].prereqLeft &= mask; aExpr[i].prereqLeft &= mask;
aExpr[i].prereqAll &= mask; aExpr[i].prereqAll &= mask;
@ -419,8 +455,9 @@ WhereInfo *sqliteWhereBegin(
loopMask = 0; loopMask = 0;
for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){ for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){
int j; int j;
int idx = i; int iCur = pTabList->a[i].iCursor; /* The cursor for this table */
Table *pTab = pTabList->a[idx].pTab; int mask = getMask(&maskSet, iCur); /* Cursor mask for this table */
Table *pTab = pTabList->a[i].pTab;
Index *pIdx; Index *pIdx;
Index *pBestIdx = 0; Index *pBestIdx = 0;
int bestScore = 0; int bestScore = 0;
@ -438,7 +475,7 @@ WhereInfo *sqliteWhereBegin(
iDirectLt[i] = -1; iDirectLt[i] = -1;
iDirectGt[i] = -1; iDirectGt[i] = -1;
for(j=0; j<nExpr; j++){ for(j=0; j<nExpr; j++){
if( aExpr[j].idxLeft==idx && aExpr[j].p->pLeft->iColumn<0 if( aExpr[j].idxLeft==iCur && aExpr[j].p->pLeft->iColumn<0
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){ && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
switch( aExpr[j].p->op ){ switch( aExpr[j].p->op ){
case TK_IN: case TK_IN:
@ -449,7 +486,7 @@ WhereInfo *sqliteWhereBegin(
case TK_GT: iDirectGt[i] = j; break; case TK_GT: iDirectGt[i] = j; break;
} }
} }
if( aExpr[j].idxRight==idx && aExpr[j].p->pRight->iColumn<0 if( aExpr[j].idxRight==iCur && aExpr[j].p->pRight->iColumn<0
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){ && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
switch( aExpr[j].p->op ){ switch( aExpr[j].p->op ){
case TK_EQ: iDirectEq[i] = j; break; case TK_EQ: iDirectEq[i] = j; break;
@ -461,7 +498,7 @@ WhereInfo *sqliteWhereBegin(
} }
} }
if( iDirectEq[i]>=0 ){ if( iDirectEq[i]>=0 ){
loopMask |= 1<<idx; loopMask |= mask;
pWInfo->a[i].pIdx = 0; pWInfo->a[i].pIdx = 0;
continue; continue;
} }
@ -500,7 +537,7 @@ WhereInfo *sqliteWhereBegin(
if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */ if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
for(j=0; j<nExpr; j++){ for(j=0; j<nExpr; j++){
if( aExpr[j].idxLeft==idx if( aExpr[j].idxLeft==iCur
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){ && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
int iColumn = aExpr[j].p->pLeft->iColumn; int iColumn = aExpr[j].p->pLeft->iColumn;
int k; int k;
@ -535,7 +572,7 @@ WhereInfo *sqliteWhereBegin(
} }
} }
} }
if( aExpr[j].idxRight==idx if( aExpr[j].idxRight==iCur
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){ && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
int iColumn = aExpr[j].p->pRight->iColumn; int iColumn = aExpr[j].p->pRight->iColumn;
int k; int k;
@ -588,7 +625,7 @@ WhereInfo *sqliteWhereBegin(
pWInfo->a[i].pIdx = pBestIdx; pWInfo->a[i].pIdx = pBestIdx;
pWInfo->a[i].score = bestScore; pWInfo->a[i].score = bestScore;
pWInfo->a[i].bRev = 0; pWInfo->a[i].bRev = 0;
loopMask |= 1<<idx; loopMask |= mask;
if( pBestIdx ){ if( pBestIdx ){
pWInfo->a[i].iCur = pParse->nTab++; pWInfo->a[i].iCur = pParse->nTab++;
pWInfo->peakNTab = pParse->nTab; pWInfo->peakNTab = pParse->nTab;
@ -619,7 +656,8 @@ WhereInfo *sqliteWhereBegin(
pSortIdx = 0; pSortIdx = 0;
}else{ }else{
int nEqCol = (pWInfo->a[0].score+4)/8; int nEqCol = (pWInfo->a[0].score+4)/8;
pSortIdx = findSortingIndex(pTab, base, *ppOrderBy, pIdx, nEqCol, &bRev); pSortIdx = findSortingIndex(pTab, pTabList->a[0].iCursor,
*ppOrderBy, pIdx, nEqCol, &bRev);
} }
if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){ if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){
if( pIdx==0 ){ if( pIdx==0 ){
@ -640,7 +678,7 @@ WhereInfo *sqliteWhereBegin(
pTab = pTabList->a[i].pTab; pTab = pTabList->a[i].pTab;
if( pTab->isTransient || pTab->pSelect ) continue; if( pTab->isTransient || pTab->pSelect ) continue;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base+i, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
if( i==0 && !pParse->schemaVerified && if( i==0 && !pParse->schemaVerified &&
(pParse->db->flags & SQLITE_InTrans)==0 ){ (pParse->db->flags & SQLITE_InTrans)==0 ){
@ -659,7 +697,7 @@ WhereInfo *sqliteWhereBegin(
loopMask = 0; loopMask = 0;
for(i=0; i<pTabList->nSrc; i++){ for(i=0; i<pTabList->nSrc; i++){
int j, k; int j, k;
int idx = i; int iCur = pTabList->a[i].iCursor;
Index *pIdx; Index *pIdx;
WhereLevel *pLevel = &pWInfo->a[i]; WhereLevel *pLevel = &pWInfo->a[i];
@ -685,9 +723,9 @@ WhereInfo *sqliteWhereBegin(
k = iDirectEq[i]; k = iDirectEq[i];
assert( k<nExpr ); assert( k<nExpr );
assert( aExpr[k].p!=0 ); assert( aExpr[k].p!=0 );
assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx ); assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
brk = pLevel->brk = sqliteVdbeMakeLabel(v); brk = pLevel->brk = sqliteVdbeMakeLabel(v);
if( aExpr[k].idxLeft==idx ){ if( aExpr[k].idxLeft==iCur ){
Expr *pX = aExpr[k].p; Expr *pX = aExpr[k].p;
if( pX->op!=TK_IN ){ if( pX->op!=TK_IN ){
sqliteExprCode(pParse, aExpr[k].p->pRight); sqliteExprCode(pParse, aExpr[k].p->pRight);
@ -711,7 +749,7 @@ WhereInfo *sqliteWhereBegin(
cont = pLevel->cont = sqliteVdbeMakeLabel(v); cont = pLevel->cont = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk); sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk);
haveKey = 0; haveKey = 0;
sqliteVdbeAddOp(v, OP_NotExists, base+idx, brk); sqliteVdbeAddOp(v, OP_NotExists, iCur, brk);
pLevel->op = OP_Noop; pLevel->op = OP_Noop;
}else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){ }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){
/* Case 2: There is an index and all terms of the WHERE clause that /* Case 2: There is an index and all terms of the WHERE clause that
@ -725,7 +763,7 @@ WhereInfo *sqliteWhereBegin(
for(k=0; k<nExpr; k++){ for(k=0; k<nExpr; k++){
Expr *pX = aExpr[k].p; Expr *pX = aExpr[k].p;
if( pX==0 ) continue; if( pX==0 ) continue;
if( aExpr[k].idxLeft==idx if( aExpr[k].idxLeft==iCur
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& pX->pLeft->iColumn==pIdx->aiColumn[j] && pX->pLeft->iColumn==pIdx->aiColumn[j]
){ ){
@ -752,7 +790,7 @@ WhereInfo *sqliteWhereBegin(
break; break;
} }
} }
if( aExpr[k].idxRight==idx if( aExpr[k].idxRight==iCur
&& aExpr[k].p->op==TK_EQ && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
@ -795,7 +833,7 @@ WhereInfo *sqliteWhereBegin(
if( i==pTabList->nSrc-1 && pushKey ){ if( i==pTabList->nSrc-1 && pushKey ){
haveKey = 1; haveKey = 1;
}else{ }else{
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
haveKey = 0; haveKey = 0;
} }
pLevel->p1 = pLevel->iCur; pLevel->p1 = pLevel->iCur;
@ -812,8 +850,8 @@ WhereInfo *sqliteWhereBegin(
k = iDirectGt[i]; k = iDirectGt[i];
assert( k<nExpr ); assert( k<nExpr );
assert( aExpr[k].p!=0 ); assert( aExpr[k].p!=0 );
assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx ); assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
if( aExpr[k].idxLeft==idx ){ if( aExpr[k].idxLeft==iCur ){
sqliteExprCode(pParse, aExpr[k].p->pRight); sqliteExprCode(pParse, aExpr[k].p->pRight);
}else{ }else{
sqliteExprCode(pParse, aExpr[k].p->pLeft); sqliteExprCode(pParse, aExpr[k].p->pLeft);
@ -822,17 +860,17 @@ WhereInfo *sqliteWhereBegin(
if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){ if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){
sqliteVdbeAddOp(v, OP_AddImm, 1, 0); sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
} }
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, brk); sqliteVdbeAddOp(v, OP_MoveTo, iCur, brk);
aExpr[k].p = 0; aExpr[k].p = 0;
}else{ }else{
sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk); sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
} }
if( iDirectLt[i]>=0 ){ if( iDirectLt[i]>=0 ){
k = iDirectLt[i]; k = iDirectLt[i];
assert( k<nExpr ); assert( k<nExpr );
assert( aExpr[k].p!=0 ); assert( aExpr[k].p!=0 );
assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx ); assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
if( aExpr[k].idxLeft==idx ){ if( aExpr[k].idxLeft==iCur ){
sqliteExprCode(pParse, aExpr[k].p->pRight); sqliteExprCode(pParse, aExpr[k].p->pRight);
}else{ }else{
sqliteExprCode(pParse, aExpr[k].p->pLeft); sqliteExprCode(pParse, aExpr[k].p->pLeft);
@ -849,10 +887,10 @@ WhereInfo *sqliteWhereBegin(
} }
start = sqliteVdbeCurrentAddr(v); start = sqliteVdbeCurrentAddr(v);
pLevel->op = OP_Next; pLevel->op = OP_Next;
pLevel->p1 = base+idx; pLevel->p1 = iCur;
pLevel->p2 = start; pLevel->p2 = start;
if( testOp!=OP_Noop ){ if( testOp!=OP_Noop ){
sqliteVdbeAddOp(v, OP_Recno, base+idx, 0); sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
sqliteVdbeAddOp(v, testOp, 0, brk); sqliteVdbeAddOp(v, testOp, 0, brk);
} }
@ -865,10 +903,10 @@ WhereInfo *sqliteWhereBegin(
brk = pLevel->brk = sqliteVdbeMakeLabel(v); brk = pLevel->brk = sqliteVdbeMakeLabel(v);
cont = pLevel->cont = sqliteVdbeMakeLabel(v); cont = pLevel->cont = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk); sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
start = sqliteVdbeCurrentAddr(v); start = sqliteVdbeCurrentAddr(v);
pLevel->op = OP_Next; pLevel->op = OP_Next;
pLevel->p1 = base+idx; pLevel->p1 = iCur;
pLevel->p2 = start; pLevel->p2 = start;
haveKey = 0; haveKey = 0;
}else{ }else{
@ -894,7 +932,7 @@ WhereInfo *sqliteWhereBegin(
for(j=0; j<nEqColumn; j++){ for(j=0; j<nEqColumn; j++){
for(k=0; k<nExpr; k++){ for(k=0; k<nExpr; k++){
if( aExpr[k].p==0 ) continue; if( aExpr[k].p==0 ) continue;
if( aExpr[k].idxLeft==idx if( aExpr[k].idxLeft==iCur
&& aExpr[k].p->op==TK_EQ && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j] && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
@ -903,7 +941,7 @@ WhereInfo *sqliteWhereBegin(
aExpr[k].p = 0; aExpr[k].p = 0;
break; break;
} }
if( aExpr[k].idxRight==idx if( aExpr[k].idxRight==iCur
&& aExpr[k].p->op==TK_EQ && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
@ -939,7 +977,7 @@ WhereInfo *sqliteWhereBegin(
for(k=0; k<nExpr; k++){ for(k=0; k<nExpr; k++){
Expr *pExpr = aExpr[k].p; Expr *pExpr = aExpr[k].p;
if( pExpr==0 ) continue; if( pExpr==0 ) continue;
if( aExpr[k].idxLeft==idx if( aExpr[k].idxLeft==iCur
&& (pExpr->op==TK_LT || pExpr->op==TK_LE) && (pExpr->op==TK_LT || pExpr->op==TK_LE)
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& pExpr->pLeft->iColumn==pIdx->aiColumn[j] && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
@ -949,7 +987,7 @@ WhereInfo *sqliteWhereBegin(
aExpr[k].p = 0; aExpr[k].p = 0;
break; break;
} }
if( aExpr[k].idxRight==idx if( aExpr[k].idxRight==iCur
&& (pExpr->op==TK_GT || pExpr->op==TK_GE) && (pExpr->op==TK_GT || pExpr->op==TK_GE)
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& pExpr->pRight->iColumn==pIdx->aiColumn[j] && pExpr->pRight->iColumn==pIdx->aiColumn[j]
@ -994,7 +1032,7 @@ WhereInfo *sqliteWhereBegin(
for(k=0; k<nExpr; k++){ for(k=0; k<nExpr; k++){
Expr *pExpr = aExpr[k].p; Expr *pExpr = aExpr[k].p;
if( pExpr==0 ) continue; if( pExpr==0 ) continue;
if( aExpr[k].idxLeft==idx if( aExpr[k].idxLeft==iCur
&& (pExpr->op==TK_GT || pExpr->op==TK_GE) && (pExpr->op==TK_GT || pExpr->op==TK_GE)
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& pExpr->pLeft->iColumn==pIdx->aiColumn[j] && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
@ -1004,7 +1042,7 @@ WhereInfo *sqliteWhereBegin(
aExpr[k].p = 0; aExpr[k].p = 0;
break; break;
} }
if( aExpr[k].idxRight==idx if( aExpr[k].idxRight==iCur
&& (pExpr->op==TK_LT || pExpr->op==TK_LE) && (pExpr->op==TK_LT || pExpr->op==TK_LE)
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& pExpr->pRight->iColumn==pIdx->aiColumn[j] && pExpr->pRight->iColumn==pIdx->aiColumn[j]
@ -1050,7 +1088,7 @@ WhereInfo *sqliteWhereBegin(
if( i==pTabList->nSrc-1 && pushKey ){ if( i==pTabList->nSrc-1 && pushKey ){
haveKey = 1; haveKey = 1;
}else{ }else{
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
haveKey = 0; haveKey = 0;
} }
@ -1060,7 +1098,7 @@ WhereInfo *sqliteWhereBegin(
pLevel->p1 = pLevel->iCur; pLevel->p1 = pLevel->iCur;
pLevel->p2 = start; pLevel->p2 = start;
} }
loopMask |= 1<<idx; loopMask |= getMask(&maskSet, iCur);
/* Insert code to test every subexpression that can be completely /* Insert code to test every subexpression that can be completely
** computed using the current set of tables. ** computed using the current set of tables.
@ -1073,7 +1111,7 @@ WhereInfo *sqliteWhereBegin(
} }
if( haveKey ){ if( haveKey ){
haveKey = 0; haveKey = 0;
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
} }
sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1); sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
aExpr[j].p = 0; aExpr[j].p = 0;
@ -1096,7 +1134,7 @@ WhereInfo *sqliteWhereBegin(
** no outer joins with DELETE and UPDATE. ** no outer joins with DELETE and UPDATE.
*/ */
haveKey = 0; haveKey = 0;
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
} }
sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1); sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
aExpr[j].p = 0; aExpr[j].p = 0;
@ -1105,8 +1143,9 @@ WhereInfo *sqliteWhereBegin(
} }
pWInfo->iContinue = cont; pWInfo->iContinue = cont;
if( pushKey && !haveKey ){ if( pushKey && !haveKey ){
sqliteVdbeAddOp(v, OP_Recno, base, 0); sqliteVdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0);
} }
freeMaskSet(&maskSet);
return pWInfo; return pWInfo;
} }
@ -1117,7 +1156,6 @@ WhereInfo *sqliteWhereBegin(
void sqliteWhereEnd(WhereInfo *pWInfo){ void sqliteWhereEnd(WhereInfo *pWInfo){
Vdbe *v = pWInfo->pParse->pVdbe; Vdbe *v = pWInfo->pParse->pVdbe;
int i; int i;
int base = pWInfo->base;
WhereLevel *pLevel; WhereLevel *pLevel;
SrcList *pTabList = pWInfo->pTabList; SrcList *pTabList = pWInfo->pTabList;
@ -1135,7 +1173,7 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
int addr; int addr;
addr = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0); addr = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);
sqliteVdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iCur>=0)); sqliteVdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iCur>=0));
sqliteVdbeAddOp(v, OP_NullRow, base+i, 0); sqliteVdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
if( pLevel->iCur>=0 ){ if( pLevel->iCur>=0 ){
sqliteVdbeAddOp(v, OP_NullRow, pLevel->iCur, 0); sqliteVdbeAddOp(v, OP_NullRow, pLevel->iCur, 0);
} }
@ -1148,7 +1186,7 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
assert( pTab!=0 ); assert( pTab!=0 );
if( pTab->isTransient || pTab->pSelect ) continue; if( pTab->isTransient || pTab->pSelect ) continue;
pLevel = &pWInfo->a[i]; pLevel = &pWInfo->a[i];
sqliteVdbeAddOp(v, OP_Close, base+i, 0); sqliteVdbeAddOp(v, OP_Close, pTabList->a[i].iCursor, 0);
if( pLevel->pIdx!=0 ){ if( pLevel->pIdx!=0 ){
sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0); sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0);
} }

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is in-memory database backend. # focus of this script is in-memory database backend.
# #
# $Id: memdb.test,v 1.2 2003/04/20 23:45:23 drh Exp $ # $Id: memdb.test,v 1.3 2003/05/02 14:32:15 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -53,15 +53,25 @@ do_test memdb-1.1 {
# make lots of changes to t3, then rollback and take another signature. # make lots of changes to t3, then rollback and take another signature.
# The two signatures should be the same. # The two signatures should be the same.
# #
proc signature {} { proc signature {{fn {}}} {
return [db eval {SELECT count(*), md5sum(x) FROM t3}] set rx [db eval {SELECT x FROM t3}]
# set r1 [md5 $rx\n]
if {$fn!=""} {
# set fd [open $fn w]
# puts $fd $rx
# close $fd
}
# set r [db eval {SELECT count(*), md5sum(x) FROM t3}]
# puts "SIG($fn)=$r1"
return [list [string length $rx] $rx]
} }
# Do rollbacks. Make sure the signature does not change. # Do rollbacks. Make sure the signature does not change.
# #
set limit 10 set limit 10
for {set i 2} {$i<=$limit} {incr i} { for {set i 2} {$i<=$limit} {incr i} {
set ::sig [signature] set ::sig [signature one]
# puts "sig=$sig"
set cnt [lindex $::sig 0] set cnt [lindex $::sig 0]
set ::journal_format [expr {($i%3)+1}] set ::journal_format [expr {($i%3)+1}]
if {$i%2==0} { if {$i%2==0} {
@ -77,8 +87,10 @@ for {set i 2} {$i<=$limit} {incr i} {
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
ROLLBACK; ROLLBACK;
} }
signature set sig2 [signature two]
} $sig } $sig
# puts "sig2=$sig2"
# if {$sig2!=$sig} exit
do_test memdb-1.$i.2-$cnt { do_test memdb-1.$i.2-$cnt {
execsql { execsql {
BEGIN; BEGIN;

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing VIEW statements. # focus of this file is testing VIEW statements.
# #
# $Id: view.test,v 1.13 2003/04/24 01:45:05 drh Exp $ # $Id: view.test,v 1.14 2003/05/02 14:32:15 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -296,6 +296,16 @@ do_test view-8.5 {
SELECT mx+10, mx*2 FROM v8; SELECT mx+10, mx*2 FROM v8;
} }
} {13 6} } {13 6}
do_test view-8.6 {
execsql {
SELECT mx+10, pqr FROM v6, v8 WHERE xyz=2;
}
} {13 7}
do_test view-8.7 {
execsql {
SELECT mx+10, pqr FROM v6, v8 WHERE xyz>2;
}
} {13 13 13 19 13 27}
# Tests for a bug found by Michiel de Wit involving ORDER BY in a VIEW. # Tests for a bug found by Michiel de Wit involving ORDER BY in a VIEW.
# #