Continued refactoring of the name resolution logic and query optimizer. (CVS 2236)

FossilOrigin-Name: d8b2a7e09187564fe66a2b4bf0992c6a017146cf
This commit is contained in:
drh 2005-01-19 23:24:50 +00:00
parent 76b047d957
commit 1398ad3639
16 changed files with 182 additions and 107 deletions

View File

@ -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

View File

@ -1 +1 @@
27cf83224c69e661c19f9a09f39bfdae75e3b0a4
d8b2a7e09187564fe66a2b4bf0992c6a017146cf

View 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);

View 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);
}

View 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;

View 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;
}
}

View 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
}
/*

View 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);
}

View 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;
}

View 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*);

View 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;
}

View 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;

View 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);
}

View 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.

View 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

View 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);