]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
VDBE cursors numbers for tables in a join do not have to be consecutive.
authordrh <drh@noemail.net>
Fri, 2 May 2003 14:32:12 +0000 (14:32 +0000)
committerdrh <drh@noemail.net>
Fri, 2 May 2003 14:32:12 +0000 (14:32 +0000)
This is one step on the road to fixing ticket #272. (CVS 947)

FossilOrigin-Name: be7aed2011b4af868b6a0c370c3d41354ae0cdf4

15 files changed:
manifest
manifest.uuid
src/auth.c
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/select.c
src/sqliteInt.h
src/trigger.c
src/update.c
src/vdbe.c
src/where.c
test/memdb.test
test/view.test

index f6a66bf714c51c6df7ddffad44b861ba4c4209f2..8e7eec4f888276166278e3ca3018ea4c1e1cef7d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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)
-D 2003-05-01T16:56:03
+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-02T14:32:13
 F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -20,19 +20,19 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
 F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
 F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
-F src/auth.c 3be3c7434592117f049703966b940e0b07088ae2
+F src/auth.c 53b8923f17f364af84501fa99dc00c779913a26d
 F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d
 F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
 F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d
-F src/build.c d35b7a6595af2ab07083b7f63bd5d22578b3c189
+F src/build.c e24461d42381a36de88de6af06c03d9f14588705
 F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263
-F src/delete.c 0f7c26aaebc417ad66a2a1099e59cc4056512c31
+F src/delete.c f9536a75b444a21f11b7a1bc0fb8c876f691b013
 F src/encode.c faf03741efe921755ec371cf4a6984536de00042
-F src/expr.c 46e2bb93abd6c70e67c8cdc5d92fdcd0b95498f3
+F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616
 F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605
 F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c 19882be1edc4b1629b8f3097e2615164f2c9cecb
+F src/insert.c c230a8c216f6788095d46f0e270406a93aae45af
 F src/main.c 5265058c9a598b4714dc9e528152b81fcb31e7ad
 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
 F src/os.c 94b618c0c0a76210e53857d77c96d2f042dc33b1
@@ -43,11 +43,11 @@ F src/parse.y 39b5240cb78047dc56d6d37c398baed7ba556779
 F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5
 F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c d1c876b9078894bc956cf1a5b38abd1a5abaf70b
+F src/select.c 493360f3003719ad61d49863c4f5db0bad9022cb
 F src/shell.c 6f59240f69e65a1c4e1d06492eb9238092defc34
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
-F src/sqliteInt.h faf133e1441b7c7b93ad5d8a58201d4849033b75
+F src/sqliteInt.h a3d84942dacaf72fbe1426adfbd37e8cf5f57e97
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
 F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
 F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
@@ -55,13 +55,13 @@ F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
 F src/tokenize.c 067d1a477a94af7712ca74e09aaa6bd0f7299527
-F src/trigger.c 62d1e1b837a98f1fa7511c77977d51c8516ddb65
-F src/update.c f40376ed2e092a7040c6fc6fa0add59fad5c5e76
+F src/trigger.c 8ee811986080de60d9d883ad96daffea82014f27
+F src/update.c dc3b680b4cf2cb6d839950b68d632850746639b9
 F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c
 F src/vacuum.c 14ac3073203fa021e01ffe33db56968ad79a8344
-F src/vdbe.c 48098080d2b5d35d4cc28ac2a4855c7730f6ee7b
+F src/vdbe.c 829fa31c2169588db7a041950cb95c6bb75811a6
 F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
-F src/where.c f632cd30f013163484a4d60c249d36fe31f5be12
+F src/where.c ef11773a07cf075740378d7d1cbabf328146fdc9
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test b311c83e370e6b22b79a8279317039440ce64862
 F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
@@ -92,7 +92,7 @@ F test/limit.test 9ffb965a0f5bf7152187ef3d8d1249b96e5620bf
 F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473
 F test/main.test a028743affca67670e24c97527d1f4ad4bc2aad3
 F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
-F test/memdb.test 4494051bcf72df58d9c631a5bc1260cba2b021cc
+F test/memdb.test 3acf1453a5705d1aa524d3027667ca3d9c77c69f
 F test/memleak.test a18e6810cae96d2f6f5136920267adbefc8e1e90
 F test/minmax.test b54ac3bc45460a4976b08ef363e05c032418726e
 F test/misc1.test 865c907df58195364eaf2e69426e9674bc8d1a8c
@@ -127,7 +127,7 @@ F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
 F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
 F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258
 F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
-F test/view.test d356f445d481c04ffa6036a4c61cb8ba70289f69
+F test/view.test 8b3b0b30674865af2c87acbdf945e369f92012a5
 F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
 F tool/lemon.c 14fedcde9cf70aa6040b89de164cf8f56f92a4b9
@@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 20fcead42bc875f13eec52971530342ff00c5eda
-R 7ac507f145c490883ec534eb0c6164c6
+P 6d019e0baa3219614a9bc5b550a0f9fe3f7e731a
+R f7e61e2db6268bcec64f93ca941fa9e1
 U drh
-Z a8877957a40cc5dcaf456e37a442b5a4
+Z affbf408d9fd8c226a5447c7e8084f51
index 3b2c1787222ddfecd9d126aa3fcdab47f6bc842b..a5fdcd2ea50ee659f9e12208495111326c371606 100644 (file)
@@ -1 +1 @@
-6d019e0baa3219614a9bc5b550a0f9fe3f7e731a
\ No newline at end of file
+be7aed2011b4af868b6a0c370c3d41354ae0cdf4
\ No newline at end of file
index 2a5a8f5648a278a427ce9c22b2d7e548375363c3..4bd4903f9e7c32ada8f74810754e777f57ae00ee 100644 (file)
@@ -14,7 +14,7 @@
 ** systems that do not need this facility may omit it by recompiling
 ** 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"
 
@@ -76,8 +76,8 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
 
 /*
 ** 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
-** this particular column.
+** is in pTabList or else it is the NEW or OLD table of a trigger.  
+** Check to see if it is OK to read this particular column.
 **
 ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN 
 ** 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(
   Parse *pParse,        /* The parser context */
   Expr *pExpr,          /* The expression to check authorization on */
-  SrcList *pTabList,    /* All table that pExpr might refer to */
-  int base              /* Offset of pTabList relative to pExpr */
+  SrcList *pTabList     /* All table that pExpr might refer to */
 ){
   sqlite *db = pParse->db;
   int rc;
@@ -98,7 +97,9 @@ void sqliteAuthRead(
 
   if( db->xAuth==0 ) return;
   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 ){
     pTab = pTabList->a[iSrc].pTab;
   }else{
index 95eb73a17d3903743cf77e9716f76458f079e6f0..a4091d81f7b2c18e8e512cd3dea81a6ac71f712a 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     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 <ctype.h>
@@ -1767,7 +1767,7 @@ void sqliteCreateIndex(
         if( pTab->iPKey==iCol ){
           sqliteVdbeAddOp(v, OP_Dup, i, 0);
         }else{
-          sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
+          sqliteVdbeAddOp(v, OP_Column, 2, iCol);
         }
       }
       sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
@@ -1993,7 +1993,7 @@ void sqliteSrcListAssignCursors(Parse *pParse, SrcList *pList){
   int i;
   for(i=0; i<pList->nSrc; i++){
     if( pList->a[i].iCursor<0 ){
-      pList->a[i].iCursor = ++pParse->nTab;
+      pList->a[i].iCursor = pParse->nTab++;
     }
   }
 }
index 14c7a20e16e74b3359f18c6c3e1a346a2bcb3f95..6c46c122d830b08c8d10c82a68cb2397100a3e43 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.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"
 
@@ -65,7 +65,7 @@ void sqliteDeleteFrom(
   int i;                 /* Loop counter */
   WhereInfo *pWInfo;     /* Information about the WHERE clause */
   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 */
   int isView;            /* True if attempting to delete from a view */
   AuthContext sContext;  /* Authorization context */
@@ -119,9 +119,10 @@ void sqliteDeleteFrom(
 
   /* 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( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
+    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
       goto delete_from_cleanup;
     }
     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@@ -149,7 +150,7 @@ void sqliteDeleteFrom(
   */
   if( isView ){
     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);
   }
 
@@ -172,13 +173,13 @@ void sqliteDeleteFrom(
       int addr;
       if( !isView ){
         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);
-      sqliteVdbeAddOp(v, OP_Next, base, addr);
+      sqliteVdbeAddOp(v, OP_Next, iCur, addr);
       sqliteVdbeResolveLabel(v, endOfLoop);
-      sqliteVdbeAddOp(v, OP_Close, base, 0);
+      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
     }
     if( !isView ){
       sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
@@ -194,7 +195,7 @@ void sqliteDeleteFrom(
   else{
     /* 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;
 
     /* Remember the key of every item to be deleted.
@@ -229,15 +230,15 @@ void sqliteDeleteFrom(
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
       if( !isView ){
         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_RowData, base, 0);
+      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
+      sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
       sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
       if( !isView ){
-        sqliteVdbeAddOp(v, OP_Close, base, 0);
+        sqliteVdbeAddOp(v, OP_Close, iCur, 0);
       }
 
       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
       ** 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_OpenWrite, base, pTab->tnum);
+      sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
         sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
         sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
@@ -267,7 +268,7 @@ void sqliteDeleteFrom(
       }
 
       /* 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
@@ -276,9 +277,9 @@ void sqliteDeleteFrom(
     if( row_triggers_exist ){
       if( !isView ){
         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, 
           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 */
     if( !row_triggers_exist ){
       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);
-      pParse->nTab = base;
+      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
+      pParse->nTab = iCur;
     }
   }
   sqliteEndWriteOperation(pParse);
@@ -341,13 +342,13 @@ void sqliteGenerateRowDelete(
   sqlite *db,        /* The database containing the index */
   Vdbe *v,           /* Generate code into this VDBE */
   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 addr;
-  addr = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
-  sqliteGenerateRowIndexDelete(db, v, pTab, base, 0);
-  sqliteVdbeAddOp(v, OP_Delete, base, count);
+  addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
+  sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
+  sqliteVdbeAddOp(v, OP_Delete, iCur, count);
   sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
 }
 
@@ -359,19 +360,19 @@ void sqliteGenerateRowDelete(
 ** These are the requirements:
 **
 **   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
-**       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.
 */
 void sqliteGenerateRowIndexDelete(
   sqlite *db,        /* The database containing the index */
   Vdbe *v,           /* Generate code into this VDBE */
   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 */
 ){
   int i;
@@ -380,17 +381,17 @@ void sqliteGenerateRowIndexDelete(
   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
     int j;
     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++){
       int idx = pIdx->aiColumn[j];
       if( idx==pTab->iPKey ){
         sqliteVdbeAddOp(v, OP_Dup, j, 0);
       }else{
-        sqliteVdbeAddOp(v, OP_Column, base, idx);
+        sqliteVdbeAddOp(v, OP_Column, iCur, idx);
       }
     }
     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
     if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
-    sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
+    sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
   }
 }
index 90f00f3aa0f1a036529719e332fba2ee114da75c..fbd15163f7ed051967cb5db795e01ab8eed0a056 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.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 <ctype.h>
@@ -194,6 +194,7 @@ SrcList *sqliteSrcListDup(SrcList *p){
     pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
     pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
     pNew->a[i].jointype = p->a[i].jointype;
+    pNew->a[i].iCursor = p->a[i].iCursor;
     pNew->a[i].pTab = 0;
     pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
     pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn);
@@ -402,13 +403,16 @@ int sqliteIsRowid(const char *z){
 */
 int sqliteExprResolveIds(
   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 */
   ExprList *pEList,  /* List of expressions used to resolve "AS" */
   Expr *pExpr        /* The expression to be analyzed. */
 ){
+  int i;
+
   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 ){
     /* Double-quoted strings (ex: "abc") are used as identifiers if
     ** possible.  Otherwise they remain as strings.  Single-quoted
@@ -430,7 +434,6 @@ int sqliteExprResolveIds(
     */
     case TK_ID: {
       int cnt = 0;      /* Number of matches */
-      int i;            /* Loop counter */
       char *z;
       int iDb = -1;
 
@@ -447,7 +450,7 @@ int sqliteExprResolveIds(
         for(j=0; j<pTab->nCol; j++){
           if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
             cnt++;
-            pExpr->iTable = i + base;
+            pExpr->iTable = pTabList->a[i].iCursor;
             pExpr->iDb = pTab->iDb;
             if( j==pTab->iPKey ){
               /* Substitute the record number for the INTEGER PRIMARY KEY */
@@ -476,7 +479,7 @@ int sqliteExprResolveIds(
       }
       if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){
         pExpr->iColumn = -1;
-        pExpr->iTable = base;
+        pExpr->iTable = pTabList->a[0].iCursor;
         pExpr->iDb = iDb;
         cnt = 1 + (pTabList->nSrc>1);
         pExpr->op = TK_COLUMN;
@@ -491,7 +494,7 @@ int sqliteExprResolveIds(
         return 1;
       }
       if( pExpr->op==TK_COLUMN ){
-        sqliteAuthRead(pParse, pExpr, pTabList, base);
+        sqliteAuthRead(pParse, pExpr, pTabList);
       }
       break; 
     }
@@ -550,13 +553,13 @@ int sqliteExprResolveIds(
           }
         }
         if( 0==(cntTab++) ){
-          pExpr->iTable = i + base;
+          pExpr->iTable = pTabList->a[i].iCursor;
           pExpr->iDb = pTab->iDb;
         }
         for(j=0; j<pTab->nCol; j++){
           if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
             cnt++;
-            pExpr->iTable = i + base;
+            pExpr->iTable = pTabList->a[i].iCursor;
             pExpr->iDb = pTab->iDb;
             /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
             pExpr->iColumn = j==pTab->iPKey ? -1 : j;
@@ -620,14 +623,14 @@ int sqliteExprResolveIds(
       sqliteExprDelete(pExpr->pRight);
       pExpr->pRight = 0;
       pExpr->op = TK_COLUMN;
-      sqliteAuthRead(pParse, pExpr, pTabList, base);
+      sqliteAuthRead(pParse, pExpr, pTabList);
       break;
     }
 
     case TK_IN: {
       Vdbe *v = sqliteGetVdbe(pParse);
       if( v==0 ) return 1;
-      if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pLeft) ){
+      if( sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
         return 1;
       }
       if( pExpr->pSelect ){
@@ -697,11 +700,11 @@ int sqliteExprResolveIds(
     /* For all else, just recursively walk the tree */
     default: {
       if( pExpr->pLeft
-      && sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pLeft) ){
+      && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
         return 1;
       }
       if( pExpr->pRight 
-      && sqliteExprResolveIds(pParse, base, pTabList, pEList, pExpr->pRight) ){
+      && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pRight) ){
         return 1;
       }
       if( pExpr->pList ){
@@ -709,7 +712,7 @@ int sqliteExprResolveIds(
         ExprList *pList = pExpr->pList;
         for(i=0; i<pList->nExpr; i++){
           Expr *pArg = pList->a[i].pExpr;
-          if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pArg) ){
+          if( sqliteExprResolveIds(pParse, pTabList, pEList, pArg) ){
             return 1;
           }
         }
index e83224a2f839a137190063246d00821b0cdccb90..71a0000902852d6288fa3e2a510bc138f7367378 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.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"
 
@@ -98,7 +98,7 @@ void sqliteInsert(
   Vdbe *v;              /* Generate code into this virtual machine */
   Index *pIdx;          /* For looping over indices of the table */
   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 */
   sqlite *db;           /* The main database structure */
   int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
@@ -245,7 +245,7 @@ void sqliteInsert(
     nColumn = pList->nExpr;
     dummy.nSrc = 0;
     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;
       }
       if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){
index 7dfdcc9f6eb52b1b0ae834dd1959813db7c18bd1..7b8733f4a8b71851048c7e87b6b3750bc107d6be 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.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"
 
@@ -296,13 +296,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
 ** will work correctly for both SQLite and Oracle8.
 */
 static int sqliteOracle8JoinFixup(
-  int base,         /* VDBE cursor number for first table in pSrc */
   SrcList *pSrc,    /* List of tables being joined */
   Expr *pWhere      /* The WHERE clause of the SELECT statement */
 ){
   int rc = 0;
   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 );
     if( idx>0 ){
       pSrc->a[idx-1].jointype &= ~JT_INNER;
@@ -311,16 +313,16 @@ static int sqliteOracle8JoinFixup(
     }
   }
   if( pWhere->pRight ){
-    rc = sqliteOracle8JoinFixup(base, pSrc, pWhere->pRight);
+    rc = sqliteOracle8JoinFixup(pSrc, pWhere->pRight);
   }
   if( pWhere->pLeft ){
-    rc |= sqliteOracle8JoinFixup(base, pSrc, pWhere->pLeft);
+    rc |= sqliteOracle8JoinFixup(pSrc, pWhere->pLeft);
   }
   if( pWhere->pList ){
     int i;
     ExprList *pList = pWhere->pList;
     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) ){
@@ -687,12 +689,11 @@ static void generateSortTail(
 */
 static void generateColumnTypes(
   Parse *pParse,      /* Parser context */
-  int base,           /* VDBE cursor corresponding to first entry in pTabList */
   SrcList *pTabList,  /* List of tables */
   ExprList *pEList    /* Expressions defining the result set */
 ){
   Vdbe *v = pParse->pVdbe;
-  int i;
+  int i, j;
   if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){
     return;
   }
@@ -701,8 +702,11 @@ static void generateColumnTypes(
     char *zType = 0;
     if( p==0 ) continue;
     if( p->op==TK_COLUMN && pTabList ){
-      Table *pTab = pTabList->a[p->iTable - base].pTab;
+      Table *pTab;
       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;
       assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
       if( iCol<0 ){
@@ -729,12 +733,11 @@ static void generateColumnTypes(
 */
 static void generateColumnNames(
   Parse *pParse,      /* Parser context */
-  int base,           /* VDBE cursor corresponding to first entry in pTabList */
   SrcList *pTabList,  /* List of tables */
   ExprList *pEList    /* Expressions defining the result set */
 ){
   Vdbe *v = pParse->pVdbe;
-  int i;
+  int i, j;
   if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
   pParse->colNamesSet = 1;
   for(i=0; i<pEList->nExpr; i++){
@@ -751,9 +754,12 @@ static void generateColumnNames(
     }
     showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0;
     if( p->op==TK_COLUMN && pTabList ){
-      Table *pTab = pTabList->a[p->iTable - base].pTab;
+      Table *pTab;
       char *zCol;
       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;
       assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
       if( iCol<0 ){
@@ -771,7 +777,7 @@ static void generateColumnNames(
         char *zName = 0;
         char *zTab;
  
-        zTab = pTabList->a[p->iTable - base].zAlias;
+        zTab = pTabList->a[j].zAlias;
         if( showFullNames || zTab==0 ) zTab = pTab->zName;
         sqliteSetString(&zName, zTab, ".", zCol, 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;
         assert( p->pEList );
         if( eDest==SRT_Callback ){
-          generateColumnNames(pParse, p->base, 0, p->pEList);
-          generateColumnTypes(pParse, p->base, p->pSrc, p->pEList);
+          generateColumnNames(pParse, 0, p->pEList);
+          generateColumnTypes(pParse, p->pSrc, p->pEList);
         }
         iBreak = sqliteVdbeMakeLabel(v);
         iCont = sqliteVdbeMakeLabel(v);
@@ -1425,8 +1431,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
       */
       assert( p->pEList );
       if( eDest==SRT_Callback ){
-        generateColumnNames(pParse, p->base, 0, p->pEList);
-        generateColumnTypes(pParse, p->base, p->pSrc, p->pEList);
+        generateColumnNames(pParse, 0, p->pEList);
+        generateColumnTypes(pParse, p->pSrc, p->pEList);
       }
       iBreak = sqliteVdbeMakeLabel(v);
       iCont = sqliteVdbeMakeLabel(v);
@@ -1466,37 +1472,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
   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
-** 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 
-** unchanged.)  When making a copy of an expression in pEList, change
-** references to columns in table iSub into references to table iTable.
+** unchanged.)
 **
 ** This routine is part of the flattening procedure.  A subquery
 ** 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
 ** of the subquery rather the result set of the subquery.
 */
-static void substExprList(ExprList*,int,ExprList*,int);  /* Forward Decl */
-static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){
+static void substExprList(ExprList*,int,ExprList*);  /* Forward Decl */
+static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
   if( pExpr==0 ) return;
   if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
     Expr *pNew;
@@ -1527,21 +1507,18 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){
     pExpr->iAgg = pNew->iAgg;
     sqliteTokenCopy(&pExpr->token, &pNew->token);
     sqliteTokenCopy(&pExpr->span, &pNew->span);
-    if( iSub!=iTable ){
-      changeTables(pExpr, iSub, iTable);
-    }
   }else{
-    substExpr(pExpr->pLeft, iTable, pEList, iSub);
-    substExpr(pExpr->pRight, iTable, pEList, iSub);
-    substExprList(pExpr->pList, iTable, pEList, iSub);
+    substExpr(pExpr->pLeft, iTable, pEList);
+    substExpr(pExpr->pRight, iTable, pEList);
+    substExprList(pExpr->pList, iTable, pEList);
   }
 }
 static void 
-substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){
+substExprList(ExprList *pList, int iTable, ExprList *pEList){
   int i;
   if( pList==0 ) return;
   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 *pSubSrc;   /* The FROM clause of the subquery */
   ExprList *pList;    /* The result set of the outer query */
+  int iParent;        /* VDBE cursor number of the pSub result set temp table */
   int i;
-  int iParent, iSub;
   Expr *pWhere;
 
   /* 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
   ** iFrom-th entry of the FROM clause in the outer query.
   */
-  iParent = p->base + iFrom;
-  iSub = pSub->base;
-  substExprList(p->pEList, iParent, pSub->pEList, iSub);
+  iParent = pSrc->a[iFrom].iCursor;
+  pSrc->a[iFrom].iCursor = pSubSrc->a[0].iCursor;
+  substExprList(p->pEList, iParent, pSub->pEList);
   pList = p->pEList;
   for(i=0; i<pList->nExpr; i++){
     Expr *pExpr;
@@ -1657,22 +1634,18 @@ static int flattenSubquery(
     }
   }
   if( isAgg ){
-    substExprList(p->pGroupBy, iParent, pSub->pEList, iSub);
-    substExpr(p->pHaving, iParent, pSub->pEList, iSub);
+    substExprList(p->pGroupBy, iParent, pSub->pEList);
+    substExpr(p->pHaving, iParent, pSub->pEList);
   }
   if( pSub->pOrderBy ){
     assert( p->pOrderBy==0 );
     p->pOrderBy = pSub->pOrderBy;
     pSub->pOrderBy = 0;
-    changeTablesInList(p->pOrderBy, iSub, iParent);
   }else if( p->pOrderBy ){
-    substExprList(p->pOrderBy, iParent, pSub->pEList, iSub);
+    substExprList(p->pOrderBy, iParent, pSub->pEList);
   }
   if( pSub->pWhere ){
     pWhere = sqliteExprDup(pSub->pWhere);
-    if( iParent!=iSub ){
-      changeTables(pWhere, iSub, iParent);
-    }
   }else{
     pWhere = 0;
   }
@@ -1680,12 +1653,9 @@ static int flattenSubquery(
     assert( p->pHaving==0 );
     p->pHaving = p->pWhere;
     p->pWhere = pWhere;
-    substExpr(p->pHaving, iParent, pSub->pEList, iSub);
+    substExpr(p->pHaving, iParent, pSub->pEList);
     if( pSub->pHaving ){
       Expr *pHaving = sqliteExprDup(pSub->pHaving);
-      if( iParent!=iSub ){
-        changeTables(pHaving, iSub, iParent);
-      }
       if( p->pHaving ){
         p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0);
       }else{
@@ -1694,13 +1664,10 @@ static int flattenSubquery(
     }
     assert( p->pGroupBy==0 );
     p->pGroupBy = sqliteExprListDup(pSub->pGroupBy);
-    if( iParent!=iSub ){
-      changeTablesInList(p->pGroupBy, iSub, iParent);
-    }
   }else if( p->pWhere==0 ){
     p->pWhere = pWhere;
   }else{
-    substExpr(p->pWhere, iParent, pSub->pEList, iSub);
+    substExpr(p->pWhere, iParent, pSub->pEList);
     if( pWhere ){
       p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
     }
@@ -1716,19 +1683,6 @@ static int flattenSubquery(
   }
   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 ){
     sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
   }
@@ -1817,8 +1771,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   v = sqliteGetVdbe(pParse);
   if( v==0 ) return 0;
   if( eDest==SRT_Callback ){
-    generateColumnNames(pParse, p->base, p->pSrc, p->pEList);
-    generateColumnTypes(pParse, p->base, p->pSrc, p->pEList);
+    generateColumnNames(pParse, p->pSrc, p->pEList);
+    generateColumnTypes(pParse, p->pSrc, p->pEList);
   }
 
   /* 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 ){
     sqliteCodeVerifySchema(pParse);
   }
-  base = p->base;
+  base = p->pSrc->a[0].iCursor;
   sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
   sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
   sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@@ -1928,7 +1882,6 @@ int sqliteSelect(
   Expr *pHaving;         /* The HAVING clause.  May be NULL */
   int isDistinct;        /* True if the DISTINCT keyword is present */
   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 */
 
   if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1;
@@ -1949,12 +1902,9 @@ int sqliteSelect(
   pHaving = p->pHaving;
   isDistinct = p->isDistinct;
 
-  /* Allocate a block of VDBE cursors, one for each table in the FROM clause.
-  ** The WHERE processing requires that the cursors for the tables in the
-  ** FROM clause be consecutive.
+  /* Allocate VDBE cursors for each table in the FROM clause
   */
-  base = p->base = pParse->nTab;
-  pParse->nTab += pTabList->nSrc;
+  sqliteSrcListAssignCursors(pParse, pTabList);
 
   /* 
   ** 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.
   */
   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;
     }
     if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){
@@ -2008,20 +1958,20 @@ int sqliteSelect(
     }
   }
   if( pWhere ){
-    if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pWhere) ){
+    if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){
       goto select_end;
     }
     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
       goto select_end;
     }
-    sqliteOracle8JoinFixup(base, pTabList, pWhere);
+    sqliteOracle8JoinFixup(pTabList, pWhere);
   }
   if( pHaving ){
     if( pGroupBy==0 ){
       sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
       goto select_end;
     }
-    if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pHaving) ){
+    if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){
       goto select_end;
     }
     if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){
@@ -2036,7 +1986,7 @@ int sqliteSelect(
         sqliteExprDelete(pE);
         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;
       }
       if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@@ -2064,7 +2014,7 @@ int sqliteSelect(
         sqliteExprDelete(pE);
         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;
       }
       if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
@@ -2102,7 +2052,7 @@ int sqliteSelect(
   ** step is skipped if the output is going to some other destination.
   */
   if( eDest==SRT_Callback ){
-    generateColumnNames(pParse, p->base, pTabList, pEList);
+    generateColumnNames(pParse, pTabList, pEList);
   }
 
   /* Set the limiter
@@ -2134,8 +2084,8 @@ int sqliteSelect(
       zSavedAuthContext = pParse->zAuthContext;
       pParse->zAuthContext = pTabList->a[i].zName;
     }
-    sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i,
-                 p, i, &isAgg);
+    sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, 
+                 pTabList->a[i].iCursor, p, i, &isAgg);
     if( pTabList->a[i].zName!=0 ){
       pParse->zAuthContext = zSavedAuthContext;
     }
@@ -2163,7 +2113,7 @@ int sqliteSelect(
   ** than a 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.
@@ -2237,7 +2187,7 @@ int sqliteSelect(
 
   /* Begin the database scan
   */
-  pWInfo = sqliteWhereBegin(pParse, p->base, pTabList, pWhere, 0, 
+  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0, 
                             pGroupBy ? 0 : &pOrderBy);
   if( pWInfo==0 ) goto select_end;
 
index cec4bc1e939535c0b486d7a8bf593fef3be3b131..f75495e00f4dc4a9047e80ee3a3b82653b8bc19d 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** 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 "sqlite.h"
@@ -717,7 +717,6 @@ struct WhereInfo {
   SrcList *pTabList;   /* List of tables in the join */
   int iContinue;       /* Jump here to continue with next record */
   int iBreak;          /* Jump here to break out of the loop */
-  int base;            /* Index of first Open opcode */
   int nLevel;          /* Number of nested loop */
   int savedNTab;       /* Value of pParse->nTab before WhereBegin() */
   int peakNTab;        /* Value of pParse->nTab after WhereBegin() */
@@ -754,7 +753,6 @@ struct Select {
   Select *pPrior;        /* Prior select in a compound select statement */
   int nLimit, nOffset;   /* LIMIT and OFFSET values.  -1 means not used */
   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*);
 SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
 void sqliteSrcListAddAlias(SrcList*, Token*);
+void sqliteSrcListAssignCursors(Parse*, SrcList*);
 void sqliteIdListDelete(IdList*);
 void sqliteSrcListDelete(SrcList*);
 void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,int,Token*,Token*);
@@ -1054,7 +1053,7 @@ Table *sqliteSrcListLookup(Parse*, SrcList*);
 int sqliteIsReadOnly(Parse*, Table*, int);
 void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
 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 sqliteExprCode(Parse*, Expr*);
 void sqliteExprIfTrue(Parse*, Expr*, int, int);
@@ -1072,7 +1071,7 @@ int sqliteExprCheck(Parse*, Expr*, int, int*);
 int sqliteExprType(Expr*);
 int sqliteExprCompare(Expr*, Expr*);
 int sqliteFuncId(Token*);
-int sqliteExprResolveIds(Parse*, int, SrcList*, ExprList*, Expr*);
+int sqliteExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
 int sqliteExprAnalyzeAggregates(Parse*, Expr*);
 Vdbe *sqliteGetVdbe(Parse*);
 int sqliteRandomByte(void);
@@ -1120,12 +1119,12 @@ int sqliteJoinType(Parse*, Token*, Token*, Token*);
 void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int);
 void sqliteDeferForeignKey(Parse*, int);
 #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*);
   void sqliteAuthContextPush(Parse*, AuthContext*, const char*);
   void sqliteAuthContextPop(AuthContext*);
 #else
-# define sqliteAuthRead(a,b,c,d)
+# define sqliteAuthRead(a,b,c)
 # define sqliteAuthCheck(a,b,c,d)    SQLITE_OK
 # define sqliteAuthContextPush(a,b,c)
 # define sqliteAuthContextPop(a)
index b07b8c5a8781f4872ec45645b44d9e5082d4e8d0..227e471534c22efe8da7f23badf4befdbfa605bd 100644 (file)
@@ -678,7 +678,7 @@ int sqliteCodeRowTrigger(
       /* code the WHEN clause */
       endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
       whenExpr = sqliteExprDup(pTrigger->pWhen);
-      if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
+      if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
         pParse->trigStack = pParse->trigStack->pNext;
         sqliteFree(pTriggerStack);
         sqliteExprDelete(whenExpr);
index cd98c82c06edb23170f8084ea2397bcde3fcac34..56021b7460d334b2296937a6eb21132359d621ac 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.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"
 
@@ -38,7 +38,7 @@ void sqliteUpdate(
   Index *pIdx;           /* For looping over indices */
   int nIdx;              /* Number of indices that need updating */
   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 */
   Index **apIdx = 0;     /* An array of indices that need updating too */
   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
   ** allocate enough space, just in case.
   */
-  base = pParse->nTab++;
+  pTabList->a[0].iCursor = iCur = pParse->nTab++;
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     pParse->nTab++;
   }
@@ -111,7 +111,7 @@ void sqliteUpdate(
   */
   chngRecno = 0;
   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;
     }
     if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
@@ -185,7 +185,7 @@ void sqliteUpdate(
   ** WHERE clause.
   */
   if( pWhere ){
-    if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
+    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
       goto update_cleanup;
     }
     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
@@ -211,13 +211,13 @@ void sqliteUpdate(
   if( isView ){
     Select *pView;
     pView = sqliteSelectDup(pTab->pSelect);
-    sqliteSelect(pParse, pView, SRT_TempTable, base, 0, 0, 0);
+    sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
     sqliteSelectDelete(pView);
   }
 
   /* 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;
 
   /* Remember the index of every item to be updated.
@@ -252,14 +252,14 @@ void sqliteUpdate(
     sqliteVdbeAddOp(v, OP_Dup, 0, 0);
     if( !isView ){
       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
     */
-    sqliteVdbeAddOp(v, OP_Recno, base, 0);
-    sqliteVdbeAddOp(v, OP_RowData, base, 0);
+    sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
+    sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
     sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
 
     /* Generate the NEW table
@@ -267,7 +267,7 @@ void sqliteUpdate(
     if( chngRecno ){
       sqliteExprCode(pParse, pRecnoExpr);
     }else{
-      sqliteVdbeAddOp(v, OP_Recno, base, 0);
+      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
     }
     for(i=0; i<pTab->nCol; i++){
       if( i==pTab->iPKey ){
@@ -276,7 +276,7 @@ void sqliteUpdate(
       }
       j = aXRef[i];
       if( j<0 ){
-        sqliteVdbeAddOp(v, OP_Column, base, i);
+        sqliteVdbeAddOp(v, OP_Column, iCur, i);
       }else{
         sqliteExprCode(pParse, pChanges->a[j].pExpr);
       }
@@ -284,7 +284,7 @@ void sqliteUpdate(
     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
     sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
     if( !isView ){
-      sqliteVdbeAddOp(v, OP_Close, base, 0);
+      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
     }
 
     /* Fire the BEFORE and INSTEAD OF triggers
@@ -303,7 +303,7 @@ void sqliteUpdate(
     ** to be deleting some records.
     */
     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 ){
       openAll = 1;
     }else{
@@ -318,8 +318,8 @@ void sqliteUpdate(
     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
       if( openAll || aIdxUsed[i] ){
         sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
-        sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum);
-        assert( pParse->nTab>base+i+1 );
+        sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
+        assert( pParse->nTab>iCur+i+1 );
       }
     }
 
@@ -334,7 +334,7 @@ void sqliteUpdate(
       addr = sqliteVdbeAddOp(v, OP_ListRead, 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
     ** will be after the update. (The old record number is currently
@@ -354,7 +354,7 @@ void sqliteUpdate(
       }
       j = aXRef[i];
       if( j<0 ){
-        sqliteVdbeAddOp(v, OP_Column, base, i);
+        sqliteVdbeAddOp(v, OP_Column, iCur, i);
       }else{
         sqliteExprCode(pParse, pChanges->a[j].pExpr);
       }
@@ -362,22 +362,22 @@ void sqliteUpdate(
 
     /* Do constraint checks
     */
-    sqliteGenerateConstraintChecks(pParse, pTab, base, aIdxUsed, chngRecno, 1,
+    sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
                                    onError, addr);
 
     /* 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( chngRecno ){
-      sqliteVdbeAddOp(v, OP_Delete, base, 0);
+      sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
     }
 
     /* 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 
@@ -393,10 +393,10 @@ void sqliteUpdate(
     if( !isView ){
       for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, 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);
-      pParse->nTab = base;
+      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
+      pParse->nTab = iCur;
     }
     if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, 
           newIdx, oldIdx, onError, addr) ){
@@ -415,11 +415,11 @@ void sqliteUpdate(
   if( !row_triggers_exist ){
     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, 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);
-    pParse->nTab = base;
+    sqliteVdbeAddOp(v, OP_Close, iCur, 0);
+    pParse->nTab = iCur;
   }else{
     sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
     sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
index 3c921d2f8a257f5b641beb80d538199ab174def5..511e76cb052a8598bf42f6326b9d85758fb65529 100644 (file)
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.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 <ctype.h>
@@ -3520,27 +3520,6 @@ case OP_OpenPseudo: {
   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 * *
 **
 ** Close a cursor previously opened as P1.  If P1 is not
index 82903047fe289079a4e9af08c315b7901340ebe1..fda6b299d8be314140396e0af964aed9eb1f487f 100644 (file)
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** 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"
 
@@ -36,6 +36,21 @@ struct ExprInfo {
   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.
 */
@@ -67,37 +82,61 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
   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
 ** 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
-** is set if table base+1 is used.  And so forth.
+** tree.
 **
 ** In order for this routine to work, the calling function must have
 ** previously invoked sqliteExprResolveIds() on the expression.  See
 ** the header comment on that routine for additional information.
-**
-** "base" is the cursor number (the value of the iTable field) that
-** corresponds to the first entry in the list of tables that appear
-** in the FROM clause of a SELECT.  For UPDATE and DELETE statements
-** there is just a single table with "base" as the cursor number.
+** The sqliteExprResolveIds() routines looks for column names and
+** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
+** the VDBE cursor number of the table.
 */
-static int exprTableUsage(int base, Expr *p){
+static int exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
   unsigned int mask = 0;
   if( p==0 ) return 0;
   if( p->op==TK_COLUMN ){
-    return 1<< (p->iTable - base);
+    return getMask(pMaskSet, p->iTable);
   }
   if( p->pRight ){
-    mask = exprTableUsage(base, p->pRight);
+    mask = exprTableUsage(pMaskSet, p->pRight);
   }
   if( p->pLeft ){
-    mask |= exprTableUsage(base, p->pLeft);
+    mask |= exprTableUsage(pMaskSet, p->pLeft);
   }
   if( p->pList ){
     int 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;
@@ -127,25 +166,22 @@ static int allowedOp(int op){
 ** "p" field filled in.  The job of this routine is to analyze the
 ** subexpression and populate all the other fields of the ExprInfo
 ** 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;
-  pInfo->prereqLeft = exprTableUsage(base, pExpr->pLeft);
-  pInfo->prereqRight = exprTableUsage(base, pExpr->pRight);
-  pInfo->prereqAll = exprTableUsage(base, pExpr);
+  pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
+  pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
+  pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
   pInfo->indexable = 0;
   pInfo->idxLeft = -1;
   pInfo->idxRight = -1;
   if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
     if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
-      pInfo->idxRight = pExpr->pRight->iTable - base;
+      pInfo->idxRight = pExpr->pRight->iTable;
       pInfo->indexable = 1;
     }
     if( pExpr->pLeft->op==TK_COLUMN ){
-      pInfo->idxLeft = pExpr->pLeft->iTable - base;
+      pInfo->idxLeft = pExpr->pLeft->iTable;
       pInfo->indexable = 1;
     }
   }
@@ -262,9 +298,9 @@ static Index *findSortingIndex(
 **      end                         /
 **
 ** There are Btree cursors associated with each table.  t1 uses cursor
-** "base".  t2 uses cursor "base+1".  And so forth.  This routine generates
-** the code to open those cursors.  sqliteWhereEnd() generates the code
-** to close them.
+** number pTabList->a[0].iCursor.  t2 uses the cursor pTabList->a[1].iCursor.
+** And so forth.  This routine generates code to open those VDBE cursors
+** and sqliteWhereEnd() generates the code to close them.
 **
 ** 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
@@ -314,7 +350,6 @@ static Index *findSortingIndex(
 */
 WhereInfo *sqliteWhereBegin(
   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 */
   Expr *pWhere,        /* The WHERE clause */
   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 loopMask;        /* One bit set for each outer loop */
   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 iDirectLt[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
   ** contains additional unfactored AND operators.
   */
+  initMaskSet(&maskSet);
   memset(aExpr, 0, sizeof(aExpr));
   nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
   if( nExpr==ARRAYSIZE(aExpr) ){
@@ -363,7 +400,6 @@ WhereInfo *sqliteWhereBegin(
   }
   pWInfo->pParse = pParse;
   pWInfo->pTabList = pTabList;
-  pWInfo->base = base;
   pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab;
   pWInfo->iBreak = sqliteVdbeMakeLabel(v);
 
@@ -378,7 +414,7 @@ WhereInfo *sqliteWhereBegin(
   /* Analyze all of the subexpressions.
   */
   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
     ** new.* and old.* tables from the prerequisite masks.
@@ -386,13 +422,13 @@ WhereInfo *sqliteWhereBegin(
     if( pParse->trigStack ){
       int x;
       if( (x = pParse->trigStack->newIdx) >= 0 ){
-        int mask = ~(1 << (x - base));
+        int mask = ~getMask(&maskSet, x);
         aExpr[i].prereqRight &= mask;
         aExpr[i].prereqLeft &= mask;
         aExpr[i].prereqAll &= mask;
       }
       if( (x = pParse->trigStack->oldIdx) >= 0 ){
-        int mask = ~(1 << (x - base));
+        int mask = ~getMask(&maskSet, x);
         aExpr[i].prereqRight &= mask;
         aExpr[i].prereqLeft &= mask;
         aExpr[i].prereqAll &= mask;
@@ -419,8 +455,9 @@ WhereInfo *sqliteWhereBegin(
   loopMask = 0;
   for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){
     int j;
-    int idx = i;
-    Table *pTab = pTabList->a[idx].pTab;
+    int iCur = pTabList->a[i].iCursor;    /* The cursor for this table */
+    int mask = getMask(&maskSet, iCur);   /* Cursor mask for this table */
+    Table *pTab = pTabList->a[i].pTab;
     Index *pIdx;
     Index *pBestIdx = 0;
     int bestScore = 0;
@@ -438,7 +475,7 @@ WhereInfo *sqliteWhereBegin(
     iDirectLt[i] = -1;
     iDirectGt[i] = -1;
     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 ){
         switch( aExpr[j].p->op ){
           case TK_IN:
@@ -449,7 +486,7 @@ WhereInfo *sqliteWhereBegin(
           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 ){
         switch( aExpr[j].p->op ){
           case TK_EQ: iDirectEq[i] = j;  break;
@@ -461,7 +498,7 @@ WhereInfo *sqliteWhereBegin(
       }
     }
     if( iDirectEq[i]>=0 ){
-      loopMask |= 1<<idx;
+      loopMask |= mask;
       pWInfo->a[i].pIdx = 0;
       continue;
     }
@@ -500,7 +537,7 @@ WhereInfo *sqliteWhereBegin(
 
       if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
       for(j=0; j<nExpr; j++){
-        if( aExpr[j].idxLeft==idx 
+        if( aExpr[j].idxLeft==iCur 
              && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
           int iColumn = aExpr[j].p->pLeft->iColumn;
           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 ){
           int iColumn = aExpr[j].p->pRight->iColumn;
           int k;
@@ -588,7 +625,7 @@ WhereInfo *sqliteWhereBegin(
     pWInfo->a[i].pIdx = pBestIdx;
     pWInfo->a[i].score = bestScore;
     pWInfo->a[i].bRev = 0;
-    loopMask |= 1<<idx;
+    loopMask |= mask;
     if( pBestIdx ){
       pWInfo->a[i].iCur = pParse->nTab++;
       pWInfo->peakNTab = pParse->nTab;
@@ -619,7 +656,8 @@ WhereInfo *sqliteWhereBegin(
        pSortIdx = 0;
      }else{
        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( pIdx==0 ){
@@ -640,7 +678,7 @@ WhereInfo *sqliteWhereBegin(
     pTab = pTabList->a[i].pTab;
     if( pTab->isTransient || pTab->pSelect ) continue;
     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);
     if( i==0 && !pParse->schemaVerified &&
           (pParse->db->flags & SQLITE_InTrans)==0 ){
@@ -659,7 +697,7 @@ WhereInfo *sqliteWhereBegin(
   loopMask = 0;
   for(i=0; i<pTabList->nSrc; i++){
     int j, k;
-    int idx = i;
+    int iCur = pTabList->a[i].iCursor;
     Index *pIdx;
     WhereLevel *pLevel = &pWInfo->a[i];
 
@@ -685,9 +723,9 @@ WhereInfo *sqliteWhereBegin(
       k = iDirectEq[i];
       assert( k<nExpr );
       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);
-      if( aExpr[k].idxLeft==idx ){
+      if( aExpr[k].idxLeft==iCur ){
         Expr *pX = aExpr[k].p;
         if( pX->op!=TK_IN ){
           sqliteExprCode(pParse, aExpr[k].p->pRight);
@@ -711,7 +749,7 @@ WhereInfo *sqliteWhereBegin(
       cont = pLevel->cont = sqliteVdbeMakeLabel(v);
       sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk);
       haveKey = 0;
-      sqliteVdbeAddOp(v, OP_NotExists, base+idx, brk);
+      sqliteVdbeAddOp(v, OP_NotExists, iCur, brk);
       pLevel->op = OP_Noop;
     }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
@@ -725,7 +763,7 @@ WhereInfo *sqliteWhereBegin(
         for(k=0; k<nExpr; k++){
           Expr *pX = aExpr[k].p;
           if( pX==0 ) continue;
-          if( aExpr[k].idxLeft==idx 
+          if( aExpr[k].idxLeft==iCur
              && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
              && pX->pLeft->iColumn==pIdx->aiColumn[j]
           ){
@@ -752,7 +790,7 @@ WhereInfo *sqliteWhereBegin(
               break;
             }
           }
-          if( aExpr[k].idxRight==idx 
+          if( aExpr[k].idxRight==iCur
              && aExpr[k].p->op==TK_EQ
              && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
              && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
@@ -795,7 +833,7 @@ WhereInfo *sqliteWhereBegin(
       if( i==pTabList->nSrc-1 && pushKey ){
         haveKey = 1;
       }else{
-        sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
+        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
         haveKey = 0;
       }
       pLevel->p1 = pLevel->iCur;
@@ -812,8 +850,8 @@ WhereInfo *sqliteWhereBegin(
         k = iDirectGt[i];
         assert( k<nExpr );
         assert( aExpr[k].p!=0 );
-        assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
-        if( aExpr[k].idxLeft==idx ){
+        assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
+        if( aExpr[k].idxLeft==iCur ){
           sqliteExprCode(pParse, aExpr[k].p->pRight);
         }else{
           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 ){
           sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
         }
-        sqliteVdbeAddOp(v, OP_MoveTo, base+idx, brk);
+        sqliteVdbeAddOp(v, OP_MoveTo, iCur, brk);
         aExpr[k].p = 0;
       }else{
-        sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
+        sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
       }
       if( iDirectLt[i]>=0 ){
         k = iDirectLt[i];
         assert( k<nExpr );
         assert( aExpr[k].p!=0 );
-        assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
-        if( aExpr[k].idxLeft==idx ){
+        assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
+        if( aExpr[k].idxLeft==iCur ){
           sqliteExprCode(pParse, aExpr[k].p->pRight);
         }else{
           sqliteExprCode(pParse, aExpr[k].p->pLeft);
@@ -849,10 +887,10 @@ WhereInfo *sqliteWhereBegin(
       }
       start = sqliteVdbeCurrentAddr(v);
       pLevel->op = OP_Next;
-      pLevel->p1 = base+idx;
+      pLevel->p1 = iCur;
       pLevel->p2 = start;
       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, testOp, 0, brk);
       }
@@ -865,10 +903,10 @@ WhereInfo *sqliteWhereBegin(
 
       brk = pLevel->brk = sqliteVdbeMakeLabel(v);
       cont = pLevel->cont = sqliteVdbeMakeLabel(v);
-      sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
+      sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
       start = sqliteVdbeCurrentAddr(v);
       pLevel->op = OP_Next;
-      pLevel->p1 = base+idx;
+      pLevel->p1 = iCur;
       pLevel->p2 = start;
       haveKey = 0;
     }else{
@@ -894,7 +932,7 @@ WhereInfo *sqliteWhereBegin(
       for(j=0; j<nEqColumn; j++){
         for(k=0; k<nExpr; k++){
           if( aExpr[k].p==0 ) continue;
-          if( aExpr[k].idxLeft==idx 
+          if( aExpr[k].idxLeft==iCur
              && aExpr[k].p->op==TK_EQ
              && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
              && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
@@ -903,7 +941,7 @@ WhereInfo *sqliteWhereBegin(
             aExpr[k].p = 0;
             break;
           }
-          if( aExpr[k].idxRight==idx 
+          if( aExpr[k].idxRight==iCur
              && aExpr[k].p->op==TK_EQ
              && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
              && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
@@ -939,7 +977,7 @@ WhereInfo *sqliteWhereBegin(
         for(k=0; k<nExpr; k++){
           Expr *pExpr = aExpr[k].p;
           if( pExpr==0 ) continue;
-          if( aExpr[k].idxLeft==idx 
+          if( aExpr[k].idxLeft==iCur
              && (pExpr->op==TK_LT || pExpr->op==TK_LE)
              && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
              && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
@@ -949,7 +987,7 @@ WhereInfo *sqliteWhereBegin(
             aExpr[k].p = 0;
             break;
           }
-          if( aExpr[k].idxRight==idx 
+          if( aExpr[k].idxRight==iCur
              && (pExpr->op==TK_GT || pExpr->op==TK_GE)
              && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
              && pExpr->pRight->iColumn==pIdx->aiColumn[j]
@@ -994,7 +1032,7 @@ WhereInfo *sqliteWhereBegin(
         for(k=0; k<nExpr; k++){
           Expr *pExpr = aExpr[k].p;
           if( pExpr==0 ) continue;
-          if( aExpr[k].idxLeft==idx 
+          if( aExpr[k].idxLeft==iCur
              && (pExpr->op==TK_GT || pExpr->op==TK_GE)
              && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
              && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
@@ -1004,7 +1042,7 @@ WhereInfo *sqliteWhereBegin(
             aExpr[k].p = 0;
             break;
           }
-          if( aExpr[k].idxRight==idx 
+          if( aExpr[k].idxRight==iCur
              && (pExpr->op==TK_LT || pExpr->op==TK_LE)
              && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
              && pExpr->pRight->iColumn==pIdx->aiColumn[j]
@@ -1050,7 +1088,7 @@ WhereInfo *sqliteWhereBegin(
       if( i==pTabList->nSrc-1 && pushKey ){
         haveKey = 1;
       }else{
-        sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
+        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
         haveKey = 0;
       }
 
@@ -1060,7 +1098,7 @@ WhereInfo *sqliteWhereBegin(
       pLevel->p1 = pLevel->iCur;
       pLevel->p2 = start;
     }
-    loopMask |= 1<<idx;
+    loopMask |= getMask(&maskSet, iCur);
 
     /* Insert code to test every subexpression that can be completely
     ** computed using the current set of tables.
@@ -1073,7 +1111,7 @@ WhereInfo *sqliteWhereBegin(
       }
       if( haveKey ){
         haveKey = 0;
-        sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
+        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
       }
       sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
       aExpr[j].p = 0;
@@ -1096,7 +1134,7 @@ WhereInfo *sqliteWhereBegin(
           ** no outer joins with DELETE and UPDATE.
           */
           haveKey = 0;
-          sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
+          sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
         }
         sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
         aExpr[j].p = 0;
@@ -1105,8 +1143,9 @@ WhereInfo *sqliteWhereBegin(
   }
   pWInfo->iContinue = cont;
   if( pushKey && !haveKey ){
-    sqliteVdbeAddOp(v, OP_Recno, base, 0);
+    sqliteVdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0);
   }
+  freeMaskSet(&maskSet);
   return pWInfo;
 }
 
@@ -1117,7 +1156,6 @@ WhereInfo *sqliteWhereBegin(
 void sqliteWhereEnd(WhereInfo *pWInfo){
   Vdbe *v = pWInfo->pParse->pVdbe;
   int i;
-  int base = pWInfo->base;
   WhereLevel *pLevel;
   SrcList *pTabList = pWInfo->pTabList;
 
@@ -1135,7 +1173,7 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
       int addr;
       addr = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 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 ){
         sqliteVdbeAddOp(v, OP_NullRow, pLevel->iCur, 0);
       }
@@ -1148,7 +1186,7 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
     assert( pTab!=0 );
     if( pTab->isTransient || pTab->pSelect ) continue;
     pLevel = &pWInfo->a[i];
-    sqliteVdbeAddOp(v, OP_Close, base+i, 0);
+    sqliteVdbeAddOp(v, OP_Close, pTabList->a[i].iCursor, 0);
     if( pLevel->pIdx!=0 ){
       sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0);
     }
index 01e356d0ae39f6b5d3fc28fdfb358681edd5ac3f..af621960430dc4763924fb4a5b1c5b7923721411 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # 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]
@@ -53,15 +53,25 @@ do_test memdb-1.1 {
 # make lots of changes to t3, then rollback and take another signature.
 # The two signatures should be the same.
 #
-proc signature {} {
-  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
+proc signature {{fn {}}} {
+  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.
 #
 set limit 10
 for {set i 2} {$i<=$limit} {incr i} {
-  set ::sig [signature]
+  set ::sig [signature one]
+  # puts "sig=$sig"
   set cnt [lindex $::sig 0]
   set ::journal_format [expr {($i%3)+1}]
   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;
        ROLLBACK;
      }
-     signature
+     set sig2 [signature two]
   } $sig
+  # puts "sig2=$sig2"
+  # if {$sig2!=$sig} exit
   do_test memdb-1.$i.2-$cnt {
      execsql {
        BEGIN;
index 3e088d169c1cfa2633dcb9e59f12faa2171ded74..57043cfc01a90e61ae37627815ecc0b7529d42f2 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # 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]
 source $testdir/tester.tcl
 
@@ -296,6 +296,16 @@ do_test view-8.5 {
     SELECT mx+10, mx*2 FROM v8;
   }
 } {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.
 #