aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c6
-rw-r--r--src/delete.c6
-rw-r--r--src/expr.c74
-rw-r--r--src/insert.c6
-rw-r--r--src/os_unix.c10
-rw-r--r--src/parse.y4
-rw-r--r--src/select.c34
-rw-r--r--src/sqliteInt.h15
-rw-r--r--src/test1.c6
-rw-r--r--src/trigger.c4
-rw-r--r--src/update.c8
-rw-r--r--src/where.c58
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.