diff options
Diffstat (limited to 'src')
-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 |
12 files changed, 148 insertions, 83 deletions
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. |