]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Continued refactoring of the name resolution logic and query optimizer. (CVS 2236)
authordrh <drh@noemail.net>
Wed, 19 Jan 2005 23:24:50 +0000 (23:24 +0000)
committerdrh <drh@noemail.net>
Wed, 19 Jan 2005 23:24:50 +0000 (23:24 +0000)
FossilOrigin-Name: d8b2a7e09187564fe66a2b4bf0992c6a017146cf

16 files changed:
manifest
manifest.uuid
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/os_unix.c
src/parse.y
src/select.c
src/sqliteInt.h
src/test1.c
src/trigger.c
src/update.c
src/where.c
test/join3.test
test/trigger1.test

index f4db7aab22a0c8302f5d56bc0eaf4bf22e647a90..803bd995ff575f39adc500968e7b8abba1a36361 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Another\sfix\salong\sthe\ssame\slines\sas\s(2234)\s(CVS\s2235)
-D 2005-01-19T03:52:55
+C Continued\srefactoring\sof\sthe\sname\sresolution\slogic\sand\squery\soptimizer.\s(CVS\s2236)
+D 2005-01-19T23:24:50
 F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -31,15 +31,15 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
 F src/btree.c 97101cce85304edbaedafc5f39ab12e2dc78b076
 F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497
-F src/build.c 608ea54aab8f561da99c8a40c3ab6b26b7fc91e9
+F src/build.c da5ecd9880f2d19d5e77fe48b722577494dd3290
 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41
 F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
-F src/delete.c 728a02e5b5c62d294f8cdbdb21dbaa3e188983ab
-F src/expr.c fdacfb27a5803eadda1a14980553ca394d1d5612
+F src/delete.c cbf54c0634c53ef683f7af8ad5c5d5637c9efb90
+F src/expr.c 7e26c70d6e9d5f6cd65da2d75fd31c87598d9e02
 F src/func.c dc188d862d7276ea897655b248e2cb17022686e3
 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
-F src/insert.c 18d506e14d200378902747d13d7fb2a43fb3d31d
+F src/insert.c e5f9a24e892259c4b1da5699f3d87287150b5e21
 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
 F src/main.c b489aae242a6123b111f125633799e37c0bab2a8
 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
@@ -47,30 +47,30 @@ F src/os.h ae44064dc118b20d39450cb331409a775e8bb1c6
 F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
 F src/os_test.c 91e5f22dd89491e5e1554820e715805f43fa4ece
 F src/os_test.h 6a26a4978492e4bbdbf385554958418ff02db162
-F src/os_unix.c 08340c864822115bf87c6c1735780a0996278b81
+F src/os_unix.c 77319e31f5284c5714239cf50ae28552286414df
 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
 F src/os_win.c 3c0b0a3bc33318cf555a1cd130232ad1b9a5a711
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
 F src/pager.c 6319578f176cbc53eb044940ce484fae244ba6c5
 F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862
-F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1
+F src/parse.y a1084470b331c1dc434e180ca888d15907bdc1cf
 F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec
 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 29bc58118d75071d1fd4f412581fde82e3e77b7d
+F src/select.c e147c81d57f7146d90a4d5a01f523dfec43808f4
 F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770
 F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611
-F src/sqliteInt.h c6414179a23cab108b4b07e8665f30829ce47f2a
+F src/sqliteInt.h a79a526b2f3c695226add233a41a5c8be3251a09
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b
-F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793
+F src/test1.c b2fd5e50457b82eff4916d1c62bd0caa10f7f4c3
 F src/test2.c bbc2ecc58ceeab12d1e40970f831b1017524e40d
 F src/test3.c a72f20066cccd5a7b9f20b7b78fa9b05b47b3020
 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
 F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
 F src/tokenize.c 88bef43fe3e3c8865a7447f934296ac13238c4f6
-F src/trigger.c 7b5da6613419da37e5b3e1c6151c7dff95fd4ee0
-F src/update.c 48da25249d33c32fa1e55c66c5a01ec0d182b203
+F src/trigger.c b3de66150300026f21522bb273bbc413a80f427d
+F src/update.c 6e5c6eb660a5508c449c6d637571e24ef13f70a1
 F src/utf.c 9bece2c7b94d9002ab1bb900a7658c6f826b0f74
 F src/util.c 63e8d77659df88b292ac2a9dbd4766419b0ea158
 F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203
@@ -80,7 +80,7 @@ F src/vdbeInt.h f2b5f54d9881bbc89fff02d95f3f825ade68bce2
 F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd
 F src/vdbeaux.c 6c294f7390880a7bb4795c9e0bc605b1a416579a
 F src/vdbemem.c 62fe89471b656a922e9879be005abf690509ead3
-F src/where.c 09defb7d1efb150d323fc253c6534d23e8a73ce6
+F src/where.c 06aa612bd0bc2634a53e541c4ed9874b814e82d1
 F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432
 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
 F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a
@@ -140,7 +140,7 @@ F test/intpkey.test b57cf5236fde1bd8cbc1388fa0c91908f6fd9194
 F test/ioerr.test fb507c2596bb07aeaff257cb48fcc93340159f0c
 F test/join.test 59e5abff5965016e3c75996f1019e2e91664647f
 F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
-F test/join3.test 67dc0d7c8dab3fff25796d0f3c3fd9c999aeded3
+F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
 F test/join4.test 8dec387d06b3a4685e1104048065cf5236b99b93
 F test/lastinsert.test b6a1db3e1ce2d3f0d6afe99d445084f543b6feaa
 F test/laststmtchanges.test 07cbdabc52407c29e40abc25050f2434f044a6b1
@@ -192,7 +192,7 @@ F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
 F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
 F test/trace.test a54fa8df0d01cf827289a7659d78959e8fd2f955
 F test/trans.test 29645b344d2b9b6792793562b12340177ddd8f96
-F test/trigger1.test 0c60435fb26db41bb2feb9549119e80857decdf1
+F test/trigger1.test 98239dd6a8baf6817a028aa8d41c7da17c6824b1
 F test/trigger2.test 534390be509127859fee7c23018f03b9bf21a88f
 F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
 F test/trigger4.test e7c0812b14750754602468f15495260e8c6625e0
@@ -269,7 +269,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
 F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746
-P 441316f1af076fef42055d6abe524f2a8c5ced63
-R b54c6e325ef9790c3c13207e79568c30
-U danielk1977
-Z 27809fc51e58df3a44c41e452ce19dca
+P 27cf83224c69e661c19f9a09f39bfdae75e3b0a4
+R 331c9226a76190b62ab0ac4aa62a5446
+U drh
+Z 621c5ade2211fc9721f7fb4569d83e10
index e87384d470cf6a5b56967585b21771b71eca6ca7..c014e6a810e0a08a60c330cce34f470081dd8066 100644 (file)
@@ -1 +1 @@
-27cf83224c69e661c19f9a09f39bfdae75e3b0a4
\ No newline at end of file
+d8b2a7e09187564fe66a2b4bf0992c6a017146cf
\ No newline at end of file
index 84cdc6cfba070b8bcd62536996b5cdbebb8f36d8..ba8bef5d2787625746cb0b12c567d6d59c1532fe 100644 (file)
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.294 2005/01/18 14:45:48 drh Exp $
+** $Id: build.c,v 1.295 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -884,7 +884,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
   }else{
     sqlite3ExprDelete(pCol->pDflt);
     pCol->pDflt = sqlite3ExprDup(pExpr);
-    sqlite3ExprResolveNames(pParse,0,0,pExpr,0,0);
+    sqlite3ExprResolveNames(pParse,0,0,0,pExpr,0,0);
   }
   sqlite3ExprDelete(pExpr);
 }
@@ -1423,7 +1423,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
       sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
       sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
       pParse->nTab = 2;
-      sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
+      sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0, 0);
       sqlite3VdbeAddOp(v, OP_Close, 1, 0);
       if( pParse->nErr==0 ){
         pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect);
index f81ec3f7ac7568526b0aad4b0c23b5129c324f2f..f7c348e6d072af7becebe3ef1a023dd71eb6d0fb 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.97 2005/01/18 04:00:44 drh Exp $
+** $Id: delete.c,v 1.98 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -150,7 +150,7 @@ void sqlite3DeleteFrom(
   */
   assert( pTabList->nSrc==1 );
   iCur = pTabList->a[0].iCursor = pParse->nTab++;
-  if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 1) ){
+  if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
     goto delete_from_cleanup;
   }
 
@@ -174,7 +174,7 @@ void sqlite3DeleteFrom(
   */
   if( isView ){
     Select *pView = sqlite3SelectDup(pTab->pSelect);
-    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
+    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
     sqlite3SelectDelete(pView);
   }
 
index 88ca91ff175835304ee28b027923d8239ddefa2d..0256934014b6de2a6484eb37ff7246703b0f012e 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.181 2005/01/18 17:20:10 drh Exp $
+** $Id: expr.c,v 1.182 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1095,6 +1095,9 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
   return 0;
 }
 
+/* Forward declaration */
+static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
+
 /*
 ** This routine walks an expression tree and resolves references to
 ** table columns.  Nodes of the form ID.ID or ID resolve into an
@@ -1117,12 +1120,13 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
 ** property on the expression.
 */
 int sqlite3ExprResolveNames(
-  Parse *pParse,     /* The parser context */
-  SrcList *pSrcList, /* 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 allowAgg,      /* True to allow aggregate expressions */
-  int codeSubquery   /* If true, then generate code for subqueries too */
+  Parse *pParse,          /* The parser context */
+  SrcList *pSrcList,      /* List of tables used to resolve column names */
+  ExprList *pEList,       /* List of expressions used to resolve "AS" */
+  NameContext *pNC,       /* Namespace of enclosing statement */
+  Expr *pExpr,            /* The expression to be analyzed. */
+  int allowAgg,           /* True to allow aggregate expressions */
+  int codeSubquery        /* If true, then generate code for subqueries too */
 ){
   NameContext sNC;
 
@@ -1132,18 +1136,29 @@ int sqlite3ExprResolveNames(
   sNC.pParse = pParse;
   sNC.pEList = pEList;
   sNC.allowAgg = allowAgg;
+  sNC.pNext = pNC;
   walkExprTree(pExpr, nameResolverStep, &sNC);
   if( sNC.hasAgg ){
     ExprSetProperty(pExpr, EP_Agg);
   }
   if( sNC.nErr>0 ){
     ExprSetProperty(pExpr, EP_Error);
-  }else if( codeSubquery  && sqlite3ExprCodeSubquery(pParse, pExpr) ){
+  }else if( codeSubquery  && sqlite3ExprCodeSubquery(pParse, &sNC, pExpr) ){
     return 1;
   }
   return ExprHasProperty(pExpr, EP_Error);
 }
 
+/*
+** A pointer instance of this structure is used to pass information
+** through walkExprTree into codeSubqueryStep().
+*/
+typedef struct QueryCoder QueryCoder;
+struct QueryCoder {
+  Parse *pParse;       /* The parsing context */
+  NameContext *pNC;    /* Namespace of first enclosing query */
+};
+
 
 /*
 ** Generate code for subqueries and IN operators.
@@ -1167,7 +1182,8 @@ int sqlite3ExprResolveNames(
 ** additional information.
 */
 static int codeSubqueryStep(void *pArg, Expr *pExpr){
-  Parse *pParse = (Parse*)pArg;
+  QueryCoder *pCoder = (QueryCoder*)pArg;
+  Parse *pParse = pCoder->pParse;
 
   switch( pExpr->op ){
     case TK_IN: {
@@ -1207,7 +1223,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
         int iParm = pExpr->iTable +  (((int)affinity)<<16);
         ExprList *pEList;
         assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
-        sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
+        sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0, 0);
         pEList = pExpr->pSelect->pEList;
         if( pEList && pEList->nExpr>0 ){ 
           keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
@@ -1237,7 +1253,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
               "right-hand side of IN operator must be constant");
             return 2;
           }
-          if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0) ){
+          if( sqlite3ExprResolveNames(pParse, 0, 0, 0, pE2, 0, 0) ){
             return 2;
           }
 
@@ -1257,8 +1273,27 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
       ** value of this select in a memory cell and record the number
       ** of the memory cell in iColumn.
       */
+      NameContext *pNC;
+      int nRef;
+      Vdbe *v;
+      int addr;
+
+      pNC = pCoder->pNC;
+      if( pNC ) nRef = pNC->nRef;
+      v = sqlite3GetVdbe(pParse);
+      addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
       pExpr->iColumn = pParse->nMem++;
-      sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0);
+      sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0,pNC);
+      if( pNC && pNC->nRef>nRef ){
+        /* Subquery value changes.  Evaluate at each use */
+        pExpr->iTable = addr+1;
+        sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+        sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+      }else{
+        /* Subquery value is constant.  evaluate only once. */
+        pExpr->iTable = -1;
+        sqlite3VdbeChangeP2(v, addr, addr+1);
+      }
       return 1;
     }
   }
@@ -1269,8 +1304,15 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
 ** Generate code to evaluate subqueries and IN operators contained
 ** in expression pExpr.
 */
-int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){
-  walkExprTree(pExpr, codeSubqueryStep, pParse);
+static int sqlite3ExprCodeSubquery(
+  Parse *pParse,       /* Parser */
+  NameContext *pNC,    /* First enclosing namespace.  Often NULL */
+  Expr *pExpr          /* Subquery to be coded */
+){
+  QueryCoder sCoder;
+  sCoder.pParse = pParse;
+  sCoder.pNC = pNC;
+  walkExprTree(pExpr, codeSubqueryStep, &sCoder);
   return 0;
 }
 
@@ -1478,6 +1520,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
       break;
     }
     case TK_SELECT: {
+      if( pExpr->iTable>=0 ){
+        sqlite3VdbeAddOp(v, OP_Gosub, 0, pExpr->iTable);
+        VdbeComment((v, "# run subquery"));
+      }
       sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
       VdbeComment((v, "# load subquery result"));
       break;
index 11b27de2cdb957f66eef0f132e069edf82b03f5d..f7de8f9bf31cd45d5c5fd0beaf190c6568fafdce 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.132 2005/01/18 04:00:44 drh Exp $
+** $Id: insert.c,v 1.133 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -312,7 +312,7 @@ void sqlite3Insert(
     iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
     iSelectLoop = sqlite3VdbeCurrentAddr(v);
     iInsertBlock = sqlite3VdbeMakeLabel(v);
-    rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
+    rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0,0);
     if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
     iCleanup = sqlite3VdbeMakeLabel(v);
     sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
@@ -380,7 +380,7 @@ void sqlite3Insert(
     nColumn = pList->nExpr;
     dummy.nSrc = 0;
     for(i=0; i<nColumn; i++){
-      if( sqlite3ExprResolveNames(pParse,&dummy,0,pList->a[i].pExpr,0,1) ){
+      if( sqlite3ExprResolveNames(pParse,&dummy,0,0,pList->a[i].pExpr,0,1) ){
         goto insert_cleanup;
       }
     }
index 3797a82cbfe1f8e4cba89ef0a66ca6229a83d7d2..bc5c0b111b3102af8aa296cc64cd56dece9babc7 100644 (file)
@@ -691,8 +691,17 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
 ** The fsync() system call does not work as advertised on many
 ** unix systems.  The following procedure is an attempt to make
 ** it work better.
+**
+** The SQLITE_NO_SYNC macro disables all fsync()s.  This is useful
+** for testing when we want to run through the test suite quickly.
+** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
+** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
+** or power failure will likely corrupt the database file.
 */
 static int full_fsync(int fd){
+#ifdef SQLITE_NO_SYNC
+  return SQLITE_OK;
+#else
   int rc;
 #ifdef F_FULLFSYNC
   rc = fcntl(fd, F_FULLFSYNC, 0);
@@ -701,6 +710,7 @@ static int full_fsync(int fd){
   rc = fsync(fd);
 #endif
   return rc;
+#endif
 }
 
 /*
index 7579361a89b947c47784fc4abc5655722690301a..84b1c46d5aa067d1289728631e6fe87238703c1f 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.158 2004/11/22 19:12:21 drh Exp $
+** @(#) $Id: parse.y,v 1.159 2005/01/19 23:24:50 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -317,7 +317,7 @@ cmd ::= DROP VIEW fullname(X). {
 //////////////////////// The SELECT statement /////////////////////////////////
 //
 cmd ::= select(X).  {
-  sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
+  sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0, 0);
   sqlite3SelectDelete(X);
 }
 
index 8295f0941cfdbbd450839fb9e25ae294262bfea6..948adc7bd0a707416c7792f066348156e04f2cdf 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.228 2005/01/18 17:40:04 drh Exp $
+** $Id: select.c,v 1.229 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -664,7 +664,7 @@ static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
   int j;
   if( pExpr==0 || pTabList==0 ) return 0;
 
-  sqlite3ExprResolveNames(pParse, pTabList, 0, pExpr, 1, 0);
+  sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pExpr, 1, 0);
   switch( pExpr->op ){
     case TK_COLUMN: {
       Table *pTab;
@@ -1468,7 +1468,7 @@ static int multiSelect(
       if( p->pOrderBy==0 ){
         pPrior->nLimit = p->nLimit;
         pPrior->nOffset = p->nOffset;
-        rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
+        rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff, 0);
         if( rc ){
           goto multi_select_end;
         }
@@ -1477,7 +1477,7 @@ static int multiSelect(
         p->iOffset = pPrior->iOffset;
         p->nLimit = -1;
         p->nOffset = 0;
-        rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
+        rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff, 0);
         p->pPrior = pPrior;
         if( rc ){
           goto multi_select_end;
@@ -1526,7 +1526,7 @@ static int multiSelect(
 
       /* Code the SELECT statements to our left
       */
-      rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
+      rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff, 0);
       if( rc ){
         goto multi_select_end;
       }
@@ -1545,7 +1545,7 @@ static int multiSelect(
       p->nLimit = -1;
       nOffset = p->nOffset;
       p->nOffset = 0;
-      rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
+      rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff, 0);
       p->pPrior = pPrior;
       p->pOrderBy = pOrderBy;
       p->nLimit = nLimit;
@@ -1614,7 +1614,7 @@ static int multiSelect(
 
       /* Code the SELECTs to our left into temporary table "tab1".
       */
-      rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
+      rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff, 0);
       if( rc ){
         goto multi_select_end;
       }
@@ -1634,7 +1634,7 @@ static int multiSelect(
       p->nLimit = -1;
       nOffset = p->nOffset;
       p->nOffset = 0;
-      rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
+      rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff, 0);
       p->pPrior = pPrior;
       p->nLimit = nLimit;
       p->nOffset = nOffset;
@@ -2216,6 +2216,7 @@ static int processOrderGroupBy(
   ExprList *pOrderBy,   /* The ORDER BY or GROUP BY clause to be processed */
   SrcList *pTabList,    /* The FROM clause */
   ExprList *pEList,     /* The result set */
+  NameContext *pNC,     /* Name context for enclosing query */
   int isAgg,            /* True if aggregate functions are involved */
   const char *zType     /* Either "ORDER" or "GROUP", as appropriate */
 ){
@@ -2228,7 +2229,7 @@ static int processOrderGroupBy(
       sqlite3ExprDelete(pE);
       pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
     }
-    if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pE, isAgg, 1) ){
+    if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pE, isAgg, 1) ){
       return 1;
     }
     if( sqlite3ExprIsConstant(pE) ){
@@ -2307,7 +2308,8 @@ int sqlite3Select(
   Select *pParent,       /* Another SELECT for which this is a sub-query */
   int parentTab,         /* Index in pParent->pSrc of this query */
   int *pParentAgg,       /* True if pParent uses aggregate functions */
-  char *aff              /* If eDest is SRT_Union, the affinity string */
+  char *aff,             /* If eDest is SRT_Union, the affinity string */
+  NameContext *pNC       /* Namespace of the next outer query */
 ){
   int i;
   WhereInfo *pWInfo;
@@ -2390,12 +2392,12 @@ int sqlite3Select(
   */
   for(i=0; i<pEList->nExpr; i++){
     Expr *pX = pEList->a[i].pExpr;
-    if( sqlite3ExprResolveNames(pParse, pTabList, 0, pX, 1, 1) ){
+    if( sqlite3ExprResolveNames(pParse, pTabList, 0, pNC, pX, 1, 1) ){
       goto select_end;
     }
     if( ExprHasProperty(pX, EP_Agg) ) isAgg = 1;
   }
-  if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pWhere, 0, 1) ){
+  if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pWhere, 0, 1) ){
     goto select_end;
   }
   if( pHaving ){
@@ -2403,7 +2405,7 @@ int sqlite3Select(
       sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
       goto select_end;
     }
-    if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pHaving, 1, 1) ){
+    if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pHaving, 1, 1) ){
       goto select_end;
     }
     if( ExprHasProperty(pHaving, EP_Agg) ) isAgg = 1;
@@ -2412,8 +2414,8 @@ int sqlite3Select(
     sqlite3ErrorMsg(pParse, "GROUP BY may only be used on aggregate queries");
     goto select_end;
   }
-  if( processOrderGroupBy(pParse, pOrderBy, pTabList, pEList, isAgg, "ORDER")
-   || processOrderGroupBy(pParse, pGroupBy, pTabList, pEList, isAgg, "GROUP")
+  if( processOrderGroupBy(pParse,pOrderBy,pTabList,pEList,pNC,isAgg,"ORDER")
+   || processOrderGroupBy(pParse,pGroupBy,pTabList,pEList,pNC,isAgg,"GROUP")
   ){
     goto select_end;
   }
@@ -2465,7 +2467,7 @@ int sqlite3Select(
       needRestoreContext = 0;
     }
     sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable, 
-                 pTabList->a[i].iCursor, p, i, &isAgg, 0);
+                 pTabList->a[i].iCursor, p, i, &isAgg, 0, 0);
     if( needRestoreContext ){
       pParse->zAuthContext = zSavedAuthContext;
     }
index 0c2bf93ad82071ce4c4d14577ab4a6e7134bcf27..ce331490a82ff4c5cd9a7787751c7661b632bdc6 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.356 2005/01/18 14:45:48 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.357 2005/01/19 23:24:51 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -787,6 +787,12 @@ struct Token {
 ** marker (a question mark character '?' in the original SQL) then the
 ** Expr.iTable holds the index number for that variable.
 **
+** If the expression is a subquery then Expr.iColumn holds an integer
+** register number containing the result of the subquery.  If the
+** subquery gives a constant result, then iTable is -1.  If the subquery
+** gives a different answer at different times during statement processing
+** then iTable is the address of a subroutine that computes the subquery.
+**
 ** The Expr.pSelect field points to a SELECT statement.  The SELECT might
 ** be the right operand of an IN operator.  Or, if a scalar SELECT appears
 ** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
@@ -1392,7 +1398,8 @@ void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
 void sqlite3DropIndex(Parse*, SrcList*);
 void sqlite3AddKeyType(Vdbe*, ExprList*);
 void sqlite3AddIdxKeyType(Vdbe*, Index*);
-int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
+int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*,
+                  char *aff, NameContext*);
 Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                         int,int,int);
 void sqlite3SelectDelete(Select*);
@@ -1422,8 +1429,8 @@ char *sqlite3NameFromToken(Token*);
 int sqlite3ExprCheck(Parse*, Expr*, int, int*);
 int sqlite3ExprCompare(Expr*, Expr*);
 int sqliteFuncId(Token*);
-int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, Expr*, int, int);
-int sqlite3ExprCodeSubquery(Parse*, Expr*);
+int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, NameContext*,
+                            Expr*, int, int);
 int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
 Vdbe *sqlite3GetVdbe(Parse*);
 void sqlite3Randomness(int, void*);
index 3684b6a1aea3578c4023873bd44c2a4d0875c815..2f9544e30ba62c159676b536549a4942fdf9fc90 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.122 2005/01/13 02:14:25 danielk1977 Exp $
+** $Id: test1.c,v 1.123 2005/01/19 23:24:51 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -2830,8 +2830,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "sqlite3_test_errstr",     test_errstr, 0             },
      { "tcl_variable_type",       tcl_variable_type, 0       },
   };
+  static int bitmask_size = sizeof(Bitmask)*8;
   int i;
   extern int sqlite3_os_trace;
 
   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
@@ -2856,6 +2858,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
   Tcl_LinkVar(interp, "sqlite_temp_directory",
       (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
+  Tcl_LinkVar(interp, "bitmask_size",
+      (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
   set_options(interp);
   return TCL_OK;
 }
index f63c7c9910b8308ed6a37c3dcc55613386eacfdf..761abfce9f2197b17d7b8ef1ba6978da27f01b52 100644 (file)
@@ -643,7 +643,7 @@ static int codeTriggerProgram(
        Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);            
        assert(ss);
        assert(ss->pSrc);
-       sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
+       sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0, 0);
        sqlite3SelectDelete(ss);
        break;
       }
@@ -766,7 +766,7 @@ int sqlite3CodeRowTrigger(
       /* code the WHEN clause */
       endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
       whenExpr = sqlite3ExprDup(pTrigger->pWhen);
-      if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, whenExpr, 0, 1) ){
+      if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, 0, whenExpr, 0,1) ){
         pParse->trigStack = trigStackEntry.pNext;
         sqlite3ExprDelete(whenExpr);
         return 1;
index 27b9c24584ecb5bb8ca55efe9aa5d84150b59b21..2158938cfb37f8dcb85dcf9bf151fe59010e551a 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.102 2005/01/18 04:00:44 drh Exp $
+** $Id: update.c,v 1.103 2005/01/19 23:24:51 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -121,7 +121,7 @@ void sqlite3Update(
   */
   chngRecno = 0;
   for(i=0; i<pChanges->nExpr; i++){
-    if( sqlite3ExprResolveNames(pParse, pTabList, 0,
+    if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0,
           pChanges->a[i].pExpr, 0, 1) ){
       goto update_cleanup;
     }
@@ -198,7 +198,7 @@ void sqlite3Update(
   /* Resolve the column names in all the expressions in the
   ** WHERE clause.
   */
-  if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 1) ){
+  if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
     goto update_cleanup;
   }
 
@@ -221,7 +221,7 @@ void sqlite3Update(
   if( isView ){
     Select *pView;
     pView = sqlite3SelectDup(pTab->pSelect);
-    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
+    sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
     sqlite3SelectDelete(pView);
   }
 
index 118c8e90e96735549dd35ded9ac083d04375d0b1..6414c4214555c540f679c670ee18cb24183bdb9b 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.129 2005/01/17 22:08:19 drh Exp $
+** $Id: where.c,v 1.130 2005/01/19 23:24:51 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -103,8 +103,8 @@ struct ExprInfo {
 */
 typedef struct ExprMaskSet ExprMaskSet;
 struct ExprMaskSet {
-  int n;                          /* Number of assigned cursor values */
-  int ix[sizeof(Bitmask)*8-1];    /* Cursor assigned to each bit */
+  int n;                        /* Number of assigned cursor values */
+  int ix[sizeof(Bitmask)*8];    /* Cursor assigned to each bit */
 };
 
 /*
@@ -152,8 +152,8 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
 #define initMaskSet(P)  memset(P, 0, sizeof(*P))
 
 /*
-** Return the bitmask for the given cursor number.  Assign a new bitmask
-** if this is the first time the cursor has been seen.
+** Return the bitmask for the given cursor number.  Return 0 if
+** iCursor is not in the set.
 */
 static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
   int i;
@@ -162,14 +162,18 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
       return ((Bitmask)1)<<i;
     }
   }
-  if( i==pMaskSet->n && i<ARRAYSIZE(pMaskSet->ix) ){
-    pMaskSet->n++;
-    pMaskSet->ix[i] = iCursor;
-    return ((Bitmask)1)<<i;
-  }
   return 0;
 }
 
+/*
+** Create a new mask for cursor iCursor.
+*/
+static void createMask(ExprMaskSet *pMaskSet, int iCursor){
+  if( pMaskSet->n<ARRAYSIZE(pMaskSet->ix) ){
+    pMaskSet->ix[pMaskSet->n++] = iCursor;
+  }
+}
+
 /*
 ** Destroy an expression mask set
 */
@@ -192,7 +196,6 @@ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
   if( p==0 ) return 0;
   if( p->op==TK_COLUMN ){
     mask = getMask(pMaskSet, p->iTable);
-    if( mask==0 ) mask = -1;
     return mask;
   }
   if( p->pRight ){
@@ -598,6 +601,15 @@ WhereInfo *sqlite3WhereBegin(
   struct SrcList_item *pTabItem;  /* A single entry from pTabList */
   WhereLevel *pLevel;             /* A single level in the pWInfo list */
 
+  /* The number of terms in the FROM clause is limited by the number of
+  ** bits in a Bitmask 
+  */
+  if( pTabList->nSrc>sizeof(Bitmask)*8 ){
+    sqlite3ErrorMsg(pParse, "at most %d tables in a join",
+       sizeof(Bitmask)*8);
+    return 0;
+  }
+
   /* Split the WHERE clause into separate subexpressions where each
   ** subexpression is separated by an AND operator.  If the aExpr[]
   ** array fills up, the last entry might point to an expression which
@@ -611,7 +623,7 @@ WhereInfo *sqlite3WhereBegin(
        "than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);
     return 0;
   }
-  
+    
   /* Allocate and initialize the WhereInfo structure that will become the
   ** return value.
   */
@@ -634,28 +646,12 @@ WhereInfo *sqlite3WhereBegin(
 
   /* Analyze all of the subexpressions.
   */
+  for(i=0; i<pTabList->nSrc; i++){
+    createMask(&maskSet, pTabList->a[i].iCursor);
+  }
   for(pTerm=aExpr, i=0; i<nExpr; i++, pTerm++){
     TriggerStack *pStack;
     exprAnalyze(pTabList, &maskSet, pTerm);
-
-    /* If we are executing a trigger body, remove all references to
-    ** new.* and old.* tables from the prerequisite masks.
-    */
-    if( (pStack = pParse->trigStack)!=0 ){
-      int x;
-      if( (x=pStack->newIdx) >= 0 ){
-        Bitmask mask = ~getMask(&maskSet, x);
-        pTerm->prereqRight &= mask;
-        pTerm->prereqLeft &= mask;
-        pTerm->prereqAll &= mask;
-      }
-      if( (x=pStack->oldIdx) >= 0 ){
-        Bitmask mask = ~getMask(&maskSet, x);
-        pTerm->prereqRight &= mask;
-        pTerm->prereqLeft &= mask;
-        pTerm->prereqAll &= mask;
-      }
-    }
   }
 
   /* Figure out what index to use (if any) for each nested loop.
index 7ce51f4089fb45cec4208a6fddab4abafd9fbce3..f1c273d1d0060f1adccd7cac432dd62390fe74d7 100644 (file)
@@ -13,7 +13,7 @@
 # This file implements tests for joins, including outer joins, where
 # there are a large number of tables involved in the join.
 #
-# $Id: join3.test,v 1.3 2004/07/20 12:45:22 drh Exp $
+# $Id: join3.test,v 1.4 2005/01/19 23:24:51 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -22,7 +22,7 @@ source $testdir/tester.tcl
 #
 catch {unset ::result}
 set result {}
-for {set N 1} {$N<=40} {incr N} {
+for {set N 1} {$N<=$bitmask_size} {incr N} {
   lappend result $N
   do_test join3-1.$N {
     execsql "CREATE TABLE t${N}(x);"
@@ -36,7 +36,7 @@ for {set N 1} {$N<=40} {incr N} {
 # Joins with a comparison
 #
 set result {}
-for {set N 1} {$N<=40} {incr N} {
+for {set N 1} {$N<=$bitmask_size} {incr N} {
   lappend result $N
   do_test join3-2.$N {
     set sql "SELECT * FROM t1"
@@ -50,4 +50,13 @@ for {set N 1} {$N<=40} {incr N} {
   } $result
 }
 
+# Error of too many tables in the join
+#
+do_test join3-3.1 {
+  set sql "SELECT * FROM t1 AS t0, t1"
+  for {set i 2} {$i<=$bitmask_size} {incr i} {append sql ", t$i"}
+  catchsql $sql
+} [list 1 "at most $bitmask_size tables in a join"]
+
+
 finish_test
index dc7ebd15755c7b32ed7d54fa357448e649f8f3eb..3118ba02cd0898a9f4e3d4f6fb4501a3163ff343 100644 (file)
@@ -146,6 +146,7 @@ do_test trigger1-1.10 {
     drop table t1;
   }
 } {2 b 4 d}
+
 do_test trigger1-1.11 {
   execsql {
     create table t1(a,b);