diff options
-rw-r--r-- | manifest | 40 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/build.c | 6 | ||||
-rw-r--r-- | src/delete.c | 6 | ||||
-rw-r--r-- | src/expr.c | 74 | ||||
-rw-r--r-- | src/insert.c | 6 | ||||
-rw-r--r-- | src/os_unix.c | 10 | ||||
-rw-r--r-- | src/parse.y | 4 | ||||
-rw-r--r-- | src/select.c | 34 | ||||
-rw-r--r-- | src/sqliteInt.h | 15 | ||||
-rw-r--r-- | src/test1.c | 6 | ||||
-rw-r--r-- | src/trigger.c | 4 | ||||
-rw-r--r-- | src/update.c | 8 | ||||
-rw-r--r-- | src/where.c | 58 | ||||
-rw-r--r-- | test/join3.test | 15 | ||||
-rw-r--r-- | test/trigger1.test | 1 |
16 files changed, 182 insertions, 107 deletions
@@ -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 diff --git a/manifest.uuid b/manifest.uuid index e87384d47..c014e6a81 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -27cf83224c69e661c19f9a09f39bfdae75e3b0a4
\ No newline at end of file +d8b2a7e09187564fe66a2b4bf0992c6a017146cf
\ No newline at end of file diff --git a/src/build.c b/src/build.c index 84cdc6cfb..ba8bef5d2 100644 --- a/src/build.c +++ b/src/build.c @@ -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); diff --git a/src/delete.c b/src/delete.c index f81ec3f7a..f7c348e6d 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** 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); } diff --git a/src/expr.c b/src/expr.c index 88ca91ff1..025693401 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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; diff --git a/src/insert.c b/src/insert.c index 11b27de2c..f7de8f9bf 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.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; } } diff --git a/src/os_unix.c b/src/os_unix.c index 3797a82cb..bc5c0b111 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -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 } /* diff --git a/src/parse.y b/src/parse.y index 7579361a8..84b1c46d5 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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); } diff --git a/src/select.c b/src/select.c index 8295f0941..948adc7bd 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.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; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0c2bf93ad..ce331490a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/src/test1.c b/src/test1.c index 3684b6a1a..2f9544e30 100644 --- a/src/test1.c +++ b/src/test1.c @@ -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; } diff --git a/src/trigger.c b/src/trigger.c index f63c7c991..761abfce9 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -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; diff --git a/src/update.c b/src/update.c index 27b9c2458..2158938cf 100644 --- a/src/update.c +++ b/src/update.c @@ -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); } diff --git a/src/where.c b/src/where.c index 118c8e90e..6414c4214 100644 --- a/src/where.c +++ b/src/where.c @@ -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,15 +162,19 @@ 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 */ #define freeMaskSet(P) /* NO-OP */ @@ -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. diff --git a/test/join3.test b/test/join3.test index 7ce51f408..f1c273d1d 100644 --- a/test/join3.test +++ b/test/join3.test @@ -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 diff --git a/test/trigger1.test b/test/trigger1.test index dc7ebd157..3118ba02c 100644 --- a/test/trigger1.test +++ b/test/trigger1.test @@ -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); |