diff --git a/manifest b/manifest index be2a887962..59180f7b34 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sreported\son\sthe\smailing\slist\sconcerning\sa\sconflict\sbetween\s"INSERT\sINTO\s...\sSELECT"\sstatements\sand\sthe\s"SELECT\smax(x)\sFROM\stbl"\soptimization.\s(CVS\s2227) -D 2005-01-17T08:57:09 +C Infrastructure\schanges\sto\shandle\sname\sresolution\sdifferently.\s\sThis\sis\sneeded\nto\sfix\svarious\slong-standing\sproblems\swith\scolumn\snames\sin\sjoins.\s\sIt\swill\nalso\smake\sthe\simplementation\sof\scorrelated\ssubqueries\seasier.\s(CVS\s2228) +D 2005-01-17T22:08:19 F Makefile.in 78d6d0af3725aef32468ac9923444d7645d21a28 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 07d50fe1b167c77f183aedd59362d55e1f579163 +F src/build.c 4638b87f5e797e364ff995f8338b281b61dd8be1 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41 F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f -F src/delete.c 32277d2834e36c7538c047f14d643751c256c73b -F src/expr.c 22bc51e18b2e686f3c831d33b2c38b5a3e6733f9 +F src/delete.c 5872f452031f31c6941ef70e9f4e1823e9fecefc +F src/expr.c 2a9485be4ec44eea0f3eada89f415f2172fc5c2e F src/func.c dc188d862d7276ea897655b248e2cb17022686e3 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 -F src/insert.c 2a8fadfd7494881632fcae453f115d42a7a58dee +F src/insert.c 0acf8a8cd21d60c60432c0004586d2aee0ad8d8e F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b F src/main.c cbe5a05baabad9fabb733065d0fb00c0b36f6ef1 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 @@ -57,10 +57,10 @@ F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1 F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c f74bdde6e77e7c351084646edbc859b08e0a3414 +F src/select.c cfd5f30611967ebd7c39d4bd448a1b1e263e9fb8 F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770 F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611 -F src/sqliteInt.h 641b348a109a080262d9f3603f2e94143d4383f2 +F src/sqliteInt.h f7ed4e6e112df9af7c85600bfb3b0af02e7b7577 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793 @@ -69,8 +69,8 @@ F src/test3.c a72f20066cccd5a7b9f20b7b78fa9b05b47b3020 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5 F src/tokenize.c c1d124ec41422c9ec14360ea3a1f98ca4acf7cf1 -F src/trigger.c 98f3b07c08ba01b34cff139ef9687883d325ae8e -F src/update.c 0979397c41ac29c54fe0cc687a356d8629a633af +F src/trigger.c 210fe50d4b3c01d3e5f8ef8a7a820117416a992b +F src/update.c 79a1511104963df3368d9235f9393cfe7f38c027 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 3a0d08505e298242f6f151f019a05129a4f8704c +F src/where.c 09defb7d1efb150d323fc253c6534d23e8a73ce6 F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a @@ -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 6244252915fa312a6c4d192464023d95aaef4661 -R 8fdfbf5efd695da44259ce4a14c6dc0d -U danielk1977 -Z f3732671f0bcdc732596f3a051a6bbad +P 5a9da62ae303800ded99942aed30eadeb3863da3 +R 27952fc035e1cac4b0d3a414cfc9fe27 +U drh +Z 916e3799f439fba92eda7a2a24dc2de5 diff --git a/manifest.uuid b/manifest.uuid index c6146e2d9d..2c09d63b5d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a9da62ae303800ded99942aed30eadeb3863da3 \ No newline at end of file +4a7534396a72ccb300303df28798bb2c50293782 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 928926a4b4..ee505d2efa 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.291 2005/01/17 07:53:44 danielk1977 Exp $ +** $Id: build.c,v 1.292 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" #include @@ -884,7 +884,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){ }else{ sqlite3ExprDelete(pCol->pDflt); pCol->pDflt = sqlite3ExprDup(pExpr); - sqlite3ExprCheck(pParse, pExpr, 0, 0); + sqlite3ExprResolveNames(pParse,0,0,pExpr,0,0,0); } sqlite3ExprDelete(pExpr); } diff --git a/src/delete.c b/src/delete.c index f29d665d3a..0bc24577ba 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.95 2005/01/10 02:48:49 danielk1977 Exp $ +** $Id: delete.c,v 1.96 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" @@ -150,7 +150,7 @@ void sqlite3DeleteFrom( */ assert( pTabList->nSrc==1 ); iCur = pTabList->a[0].iCursor = pParse->nTab++; - if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 0, 1) ){ goto delete_from_cleanup; } diff --git a/src/expr.c b/src/expr.c index 8e125624af..7c0fb70cbb 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.178 2005/01/15 01:52:32 drh Exp $ +** $Id: expr.c,v 1.179 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" #include @@ -62,8 +62,8 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ } /* -** pExpr is the left operand of a comparison operator. aff2 is the -** type affinity of the right operand. This routine returns the +** pExpr is an operand of a comparison operator. aff2 is the +** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ @@ -560,6 +560,59 @@ void sqlite3ExprListDelete(ExprList *pList){ sqliteFree(pList); } +/* +** Walk an expression tree. Call xFunc for each node visited. +** The return value from xFunc determines whether the tree walk continues. +** 0 means continue walking the tree. 1 means do not walk children +** of the current node but continue with siblings. 2 means abandon +** the tree walk completely. +** +** The return value from this routine is 1 to abandon the tree walk +** and 0 to continue. +*/ +static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){ + ExprList *pList; + int rc; + if( pExpr==0 ) return 0; + rc = (*xFunc)(pArg, pExpr); + if( rc==0 ){ + if( walkExprTree(pExpr->pLeft, xFunc, pArg) ) return 1; + if( walkExprTree(pExpr->pRight, xFunc, pArg) ) return 1; + pList = pExpr->pList; + if( pList ){ + int i; + struct ExprList_item *pItem; + for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ + if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1; + } + } + } + return rc>1; +} + +/* +** This routine is designed as an xFunc for walkExprTree(). +** +** pArg is really a pointer to an integer. If we can tell by looking +** at just pExpr and none of its children that the expression is a +** constant, then set *pArg to 1 and return 0. If we can tell that +** the expression is not a constant, then set *pArg to 0 and return 0. +** If we need to look at child nodes, return 1. +*/ +static int exprNodeIsConstant(void *pArg, Expr *pExpr){ + switch( pExpr->op ){ + case TK_ID: + case TK_COLUMN: + case TK_DOT: + case TK_AGG_FUNCTION: + case TK_FUNCTION: + *((int*)pArg) = 0; + return 2; + default: + return 0; + } +} + /* ** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables. @@ -569,35 +622,9 @@ void sqlite3ExprListDelete(ExprList *pList){ ** a constant. */ int sqlite3ExprIsConstant(Expr *p){ - switch( p->op ){ - case TK_ID: - case TK_COLUMN: - case TK_DOT: - case TK_FUNCTION: - return 0; - case TK_NULL: - case TK_STRING: - case TK_BLOB: - case TK_INTEGER: - case TK_FLOAT: - case TK_VARIABLE: - case TK_CTIME: - case TK_CTIMESTAMP: - case TK_CDATE: - return 1; - default: { - if( p->pLeft && !sqlite3ExprIsConstant(p->pLeft) ) return 0; - if( p->pRight && !sqlite3ExprIsConstant(p->pRight) ) return 0; - if( p->pList ){ - int i; - for(i=0; ipList->nExpr; i++){ - if( !sqlite3ExprIsConstant(p->pList->a[i].pExpr) ) return 0; - } - } - return p->pLeft!=0 || p->pRight!=0 || (p->pList && p->pList->nExpr>0); - } - } - return 0; + int isConst = 1; + walkExprTree(p, exprNodeIsConstant, &isConst); + return isConst; } /* @@ -670,8 +697,7 @@ static int lookupName( Token *pDbToken, /* Name of the database containing table, or NULL */ Token *pTableToken, /* Name of table containing column, or NULL */ Token *pColumnToken, /* Name of the column. */ - SrcList *pSrcList, /* List of tables used to resolve column names */ - ExprList *pEList, /* List of expressions used to resolve "AS" */ + NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ ){ char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */ @@ -680,7 +706,7 @@ static int lookupName( int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ - sqlite3 *db = pParse->db; /* The database */ + sqlite3 *db = pParse->db; /* The database */ struct SrcList_item *pItem; /* Use for looping over pSrcList items */ struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ @@ -691,73 +717,44 @@ static int lookupName( if( sqlite3_malloc_failed ){ return 1; /* Leak memory (zDb and zTab) if malloc fails */ } - assert( zTab==0 || pEList==0 ); pExpr->iTable = -1; - for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ - Table *pTab = pItem->pTab; - Column *pCol; + while( pNC && cnt==0 ){ + SrcList *pSrcList = pNC->pSrcList; + ExprList *pEList = pNC->pEList; - if( pTab==0 ) continue; - assert( pTab->nCol>0 ); - if( zTab ){ - if( pItem->zAlias ){ - char *zTabName = pItem->zAlias; - if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; - }else{ - char *zTabName = pTab->zName; - if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue; - if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ - continue; + pNC->nRef++; + /* assert( zTab==0 || pEList==0 ); */ + for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ + Table *pTab = pItem->pTab; + Column *pCol; + + if( pTab==0 ) continue; + assert( pTab->nCol>0 ); + if( zTab ){ + if( pItem->zAlias ){ + char *zTabName = pItem->zAlias; + if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; + }else{ + char *zTabName = pTab->zName; + if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue; + if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ + continue; + } } } - } - if( 0==(cntTab++) ){ - pExpr->iTable = pItem->iCursor; - pExpr->iDb = pTab->iDb; - pMatch = pItem; - } - for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ - cnt++; + if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; - pMatch = pItem; pExpr->iDb = pTab->iDb; - /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ - pExpr->iColumn = j==pTab->iPKey ? -1 : j; - pExpr->affinity = pTab->aCol[j].affinity; - pExpr->pColl = pTab->aCol[j].pColl; - break; + pMatch = pItem; } - } - } - -#ifndef SQLITE_OMIT_TRIGGER - /* If we have not already resolved the name, then maybe - ** it is a new.* or old.* trigger argument reference - */ - if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){ - TriggerStack *pTriggerStack = pParse->trigStack; - Table *pTab = 0; - if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){ - pExpr->iTable = pTriggerStack->newIdx; - assert( pTriggerStack->pTab ); - pTab = pTriggerStack->pTab; - }else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab) == 0 ){ - pExpr->iTable = pTriggerStack->oldIdx; - assert( pTriggerStack->pTab ); - pTab = pTriggerStack->pTab; - } - - if( pTab ){ - int j; - Column *pCol = pTab->aCol; - - pExpr->iDb = pTab->iDb; - cntTab++; - for(j=0; j < pTab->nCol; j++, pCol++) { + for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ cnt++; + pExpr->iTable = pItem->iCursor; + pMatch = pItem; + pExpr->iDb = pTab->iDb; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; pExpr->pColl = pTab->aCol[j].pColl; @@ -765,43 +762,85 @@ static int lookupName( } } } - } + +#ifndef SQLITE_OMIT_TRIGGER + /* If we have not already resolved the name, then maybe + ** it is a new.* or old.* trigger argument reference + */ + if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){ + TriggerStack *pTriggerStack = pParse->trigStack; + Table *pTab = 0; + if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){ + pExpr->iTable = pTriggerStack->newIdx; + assert( pTriggerStack->pTab ); + pTab = pTriggerStack->pTab; + }else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab)==0 ){ + pExpr->iTable = pTriggerStack->oldIdx; + assert( pTriggerStack->pTab ); + pTab = pTriggerStack->pTab; + } + + if( pTab ){ + int j; + Column *pCol = pTab->aCol; + + pExpr->iDb = pTab->iDb; + cntTab++; + for(j=0; j < pTab->nCol; j++, pCol++) { + if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + cnt++; + pExpr->iColumn = j==pTab->iPKey ? -1 : j; + pExpr->affinity = pTab->aCol[j].affinity; + pExpr->pColl = pTab->aCol[j].pColl; + break; + } + } + } + } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ - /* - ** Perhaps the name is a reference to the ROWID - */ - if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){ - cnt = 1; - pExpr->iColumn = -1; - pExpr->affinity = SQLITE_AFF_INTEGER; - } + /* + ** Perhaps the name is a reference to the ROWID + */ + if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){ + cnt = 1; + pExpr->iColumn = -1; + pExpr->affinity = SQLITE_AFF_INTEGER; + } - /* - ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z - ** might refer to an result-set alias. This happens, for example, when - ** we are resolving names in the WHERE clause of the following command: - ** - ** SELECT a+b AS x FROM table WHERE x<10; - ** - ** In cases like this, replace pExpr with a copy of the expression that - ** forms the result set entry ("a+b" in the example) and return immediately. - ** Note that the expression in the result set should have already been - ** resolved by the time the WHERE clause is resolved. - */ - if( cnt==0 && pEList!=0 ){ - for(j=0; jnExpr; j++){ - char *zAs = pEList->a[j].zName; - if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ - assert( pExpr->pLeft==0 && pExpr->pRight==0 ); - pExpr->op = TK_AS; - pExpr->iColumn = j; - pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr); - sqliteFree(zCol); - assert( zTab==0 && zDb==0 ); - return 0; - } - } + /* + ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z + ** might refer to an result-set alias. This happens, for example, when + ** we are resolving names in the WHERE clause of the following command: + ** + ** SELECT a+b AS x FROM table WHERE x<10; + ** + ** In cases like this, replace pExpr with a copy of the expression that + ** forms the result set entry ("a+b" in the example) and return immediately. + ** Note that the expression in the result set should have already been + ** resolved by the time the WHERE clause is resolved. + */ + if( cnt==0 && pEList!=0 ){ + for(j=0; jnExpr; j++){ + char *zAs = pEList->a[j].zName; + if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ + assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + pExpr->op = TK_AS; + pExpr->iColumn = j; + pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr); + sqliteFree(zCol); + assert( zTab==0 && zDb==0 ); + return 0; + } + } + } + + /* Advance to the next name context. The loop will exit when either + ** we have a match (cnt>0) or when we run out of name contexts. + */ + if( cnt==0 ){ + pNC = pNC->pNext; + } } /* @@ -860,10 +899,195 @@ static int lookupName( sqlite3ExprDelete(pExpr->pRight); pExpr->pRight = 0; pExpr->op = TK_COLUMN; - sqlite3AuthRead(pParse, pExpr, pSrcList); + if( cnt==1 ){ + assert( pNC!=0 && pNC->pSrcList!=0 ); + sqlite3AuthRead(pParse, pExpr, pNC->pSrcList); + } return cnt!=1; } +/* +** pExpr is a node that defines a function of some kind. It might +** be a syntactic function like "count(x)" or it might be a function +** that implements an operator, like "a LIKE b". +** +** This routine makes *pzName point to the name of the function and +** *pnName hold the number of characters in the function name. +*/ +static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){ + switch( pExpr->op ){ + case TK_FUNCTION: { + *pzName = pExpr->token.z; + *pnName = pExpr->token.n; + break; + } + case TK_LIKE: { + *pzName = "like"; + *pnName = 4; + break; + } + case TK_GLOB: { + *pzName = "glob"; + *pnName = 4; + break; + } + case TK_CTIME: { + *pzName = "current_time"; + *pnName = 12; + break; + } + case TK_CDATE: { + *pzName = "current_date"; + *pnName = 12; + break; + } + case TK_CTIMESTAMP: { + *pzName = "current_timestamp"; + *pnName = 17; + break; + } + default: { + *pzName = "can't happen"; + *pnName = 12; + break; + } + } +} + +/* +** This routine is designed as an xFunc for walkExprTree(). +** +** Resolve symbolic names into TK_COLUMN operands for the current +** node in the expression tree. Return 0 to continue the search down +** the tree or 1 to abort the tree walk. +*/ +static int nameResolverStep(void *pArg, Expr *pExpr){ + NameContext *pNC = (NameContext*)pArg; + SrcList *pSrcList; + Parse *pParse; + int i; + + assert( pNC!=0 ); + pSrcList = pNC->pSrcList; + pParse = pNC->pParse; + if( pExpr==0 ) return 1; + if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1; + ExprSetProperty(pExpr, EP_Resolved); +#ifndef NDEBUG + if( pSrcList ){ + for(i=0; inSrc; i++){ + assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab); + } + } +#endif + switch( pExpr->op ){ + /* Double-quoted strings (ex: "abc") are used as identifiers if + ** possible. Otherwise they remain as strings. Single-quoted + ** strings (ex: 'abc') are always string literals. + */ + case TK_STRING: { + if( pExpr->token.z[0]=='\'' ) break; + /* Fall thru into the TK_ID case if this is a double-quoted string */ + } + /* A lone identifier is the name of a column. + */ + case TK_ID: { + if( pSrcList==0 ) break; + lookupName(pParse, 0, 0, &pExpr->token, pNC, pExpr); + return 1; + } + + /* A table name and column name: ID.ID + ** Or a database, table and column: ID.ID.ID + */ + case TK_DOT: { + Token *pColumn; + Token *pTable; + Token *pDb; + Expr *pRight; + + if( pSrcList==0 ) break; + pRight = pExpr->pRight; + if( pRight->op==TK_ID ){ + pDb = 0; + pTable = &pExpr->pLeft->token; + pColumn = &pRight->token; + }else{ + assert( pRight->op==TK_DOT ); + pDb = &pExpr->pLeft->token; + pTable = &pRight->pLeft->token; + pColumn = &pRight->pRight->token; + } + lookupName(pParse, pDb, pTable, pColumn, pNC, pExpr); + return 1; + } + + /* Resolve function names + */ + case TK_CTIME: + case TK_CTIMESTAMP: + case TK_CDATE: + /* Note: The above three were a seperate case in sqlmoto. Reason? */ + case TK_GLOB: + case TK_LIKE: + case TK_FUNCTION: { + ExprList *pList = pExpr->pList; /* The argument list */ + int n = pList ? pList->nExpr : 0; /* Number of arguments */ + int no_such_func = 0; /* True if no such function exists */ + int wrong_num_args = 0; /* True if wrong number of arguments */ + int is_agg = 0; /* True if is an aggregate function */ + int i; + int nId; /* Number of characters in function name */ + const char *zId; /* The function name. */ + FuncDef *pDef; + int enc = pParse->db->enc; + NameContext ncParam; /* Name context for parameters */ + + getFunctionName(pExpr, &zId, &nId); + pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); + if( pDef==0 ){ + pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); + if( pDef==0 ){ + no_such_func = 1; + }else{ + wrong_num_args = 1; + } + }else{ + is_agg = pDef->xFunc==0; + } + if( is_agg && !pNC->allowAgg ){ + sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); + pNC->nErr++; + is_agg = 0; + }else if( no_such_func ){ + sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); + pNC->nErr++; + }else if( wrong_num_args ){ + sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", + nId, zId); + pNC->nErr++; + } + if( is_agg ){ + pExpr->op = TK_AGG_FUNCTION; + pNC->hasAgg = 1; + } + ncParam = *pNC; + if( is_agg ) ncParam.allowAgg = 0; + for(i=0; pNC->nErr==0 && ia[i].pExpr, nameResolverStep, &ncParam); + pNC->nErr += ncParam.nErr; + if( ncParam.hasAgg ) pNC->hasAgg = 1; + } + if( pNC->nErr ) return 2; + /* FIX ME: Compute pExpr->affinity based on the expected return + ** type of the function + */ + return is_agg; + } + } + return 0; +} + /* ** This routine walks an expression tree and resolves references to ** table columns. Nodes of the form ID.ID or ID resolve into an @@ -877,8 +1101,43 @@ static int lookupName( ** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an ** alias for ROWID. ** -** We also check for instances of the IN operator. IN comes in two -** forms: +** Also resolve function names and check the functions for proper +** usage. Make sure all function names are recognized and all functions +** have the correct number of arguments. Leave an error message +** in pParse->zErrMsg if anything is amiss. Return the number of errors. +** +** if pIsAgg is not null and this expression is an aggregate function +** (like count(*) or max(value)) then write a 1 into *pIsAgg. +*/ +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 *pIsAgg, /* Set to TRUE if aggregates are found */ + int codeSubquery /* If true, then generate code for subqueries too */ +){ + NameContext sNC; + + memset(&sNC, 0, sizeof(sNC)); + sNC.pSrcList = pSrcList; + sNC.pParse = pParse; + sNC.pEList = pEList; + sNC.allowAgg = allowAgg; + walkExprTree(pExpr, nameResolverStep, &sNC); + if( pIsAgg && sNC.hasAgg ) *pIsAgg = 1; + if( sNC.nErr==0 && codeSubquery ){ + sNC.nErr += sqlite3ExprCodeSubquery(pParse, pExpr); + } + return sNC.nErr + pParse->nErr; +} + + +/* +** Generate code for subqueries and IN operators. +** +** IN comes in two forms: ** ** expr IN (exprlist) ** and @@ -891,76 +1150,18 @@ static int lookupName( ** This routine also looks for scalar SELECTs that are part of an expression. ** If it finds any, it generates code to write the value of that select ** into a memory cell. -** -** Unknown columns or tables provoke an error. The function returns -** the number of errors seen and leaves an error message on pParse->zErrMsg. */ -int sqlite3ExprResolveIds( - 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 i; +static int codeSubqueryStep(void *pArg, Expr *pExpr){ + Parse *pParse = (Parse*)pArg; - if( pExpr==0 || pSrcList==0 ) return 0; - for(i=0; inSrc; i++){ - assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab ); - } switch( pExpr->op ){ - /* Double-quoted strings (ex: "abc") are used as identifiers if - ** possible. Otherwise they remain as strings. Single-quoted - ** strings (ex: 'abc') are always string literals. - */ - case TK_STRING: { - if( pExpr->token.z[0]=='\'' ) break; - /* Fall thru into the TK_ID case if this is a double-quoted string */ - } - /* A lone identifier is the name of a columnd. - */ - case TK_ID: { - if( lookupName(pParse, 0, 0, &pExpr->token, pSrcList, pEList, pExpr) ){ - return 1; - } - break; - } - - /* A table name and column name: ID.ID - ** Or a database, table and column: ID.ID.ID - */ - case TK_DOT: { - Token *pColumn; - Token *pTable; - Token *pDb; - Expr *pRight; - - pRight = pExpr->pRight; - if( pRight->op==TK_ID ){ - pDb = 0; - pTable = &pExpr->pLeft->token; - pColumn = &pRight->token; - }else{ - assert( pRight->op==TK_DOT ); - pDb = &pExpr->pLeft->token; - pTable = &pRight->pLeft->token; - pColumn = &pRight->pRight->token; - } - if( lookupName(pParse, pDb, pTable, pColumn, pSrcList, 0, pExpr) ){ - return 1; - } - break; - } - case TK_IN: { char affinity; Vdbe *v = sqlite3GetVdbe(pParse); KeyInfo keyInfo; int addr; /* Address of OP_OpenTemp instruction */ - if( v==0 ) return 1; - if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){ - return 1; - } + if( v==0 ) return 2; affinity = sqlite3ExprAffinity(pExpr->pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' @@ -1019,10 +1220,10 @@ int sqlite3ExprResolveIds( if( !sqlite3ExprIsConstant(pE2) ){ sqlite3ErrorMsg(pParse, "right-hand side of IN operator must be constant"); - return 1; + return 2; } - if( sqlite3ExprCheck(pParse, pE2, 0, 0) ){ - return 1; + if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0, 0) ){ + return 2; } /* Evaluate the expression and insert it into the temp table */ @@ -1033,8 +1234,7 @@ int sqlite3ExprResolveIds( } } sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO); - - break; + return 1; } case TK_SELECT: { @@ -1043,191 +1243,19 @@ int sqlite3ExprResolveIds( ** of the memory cell in iColumn. */ pExpr->iColumn = pParse->nMem++; - if(sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0)){ - return 1; - } - break; - } - - /* For all else, just recursively walk the tree */ - default: { - if( pExpr->pLeft - && sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){ - return 1; - } - if( pExpr->pRight - && sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pRight) ){ - return 1; - } - if( pExpr->pList ){ - int i; - ExprList *pList = pExpr->pList; - for(i=0; inExpr; i++){ - Expr *pArg = pList->a[i].pExpr; - if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pArg) ){ - return 1; - } - } - } + sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0); + return 1; } } return 0; } /* -** pExpr is a node that defines a function of some kind. It might -** be a syntactic function like "count(x)" or it might be a function -** that implements an operator, like "a LIKE b". -** -** This routine makes *pzName point to the name of the function and -** *pnName hold the number of characters in the function name. +** Generate code to evaluate subqueries and IN operators. */ -static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){ - switch( pExpr->op ){ - case TK_FUNCTION: { - *pzName = pExpr->token.z; - *pnName = pExpr->token.n; - break; - } - case TK_LIKE: { - *pzName = "like"; - *pnName = 4; - break; - } - case TK_GLOB: { - *pzName = "glob"; - *pnName = 4; - break; - } - case TK_CTIME: { - *pzName = "current_time"; - *pnName = 12; - break; - } - case TK_CDATE: { - *pzName = "current_date"; - *pnName = 12; - break; - } - case TK_CTIMESTAMP: { - *pzName = "current_timestamp"; - *pnName = 17; - break; - } - default: { - *pzName = "can't happen"; - *pnName = 12; - break; - } - } -} - -/* -** Error check the functions in an expression. Make sure all -** function names are recognized and all functions have the correct -** number of arguments. Leave an error message in pParse->zErrMsg -** if anything is amiss. Return the number of errors. -** -** if pIsAgg is not null and this expression is an aggregate function -** (like count(*) or max(value)) then write a 1 into *pIsAgg. -*/ -int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ - int nErr = 0; - if( pExpr==0 ) return 0; - switch( pExpr->op ){ - case TK_CTIME: - case TK_CTIMESTAMP: - case TK_CDATE: - /* Note: The above three were a seperate case in sqlmoto. Reason? */ - case TK_GLOB: - case TK_LIKE: - case TK_FUNCTION: { - int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */ - int no_such_func = 0; /* True if no such function exists */ - int wrong_num_args = 0; /* True if wrong number of arguments */ - int is_agg = 0; /* True if is an aggregate function */ - int i; - int nId; /* Number of characters in function name */ - const char *zId; /* The function name. */ - FuncDef *pDef; - int enc = pParse->db->enc; - - getFunctionName(pExpr, &zId, &nId); - pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); - if( pDef==0 ){ - pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); - if( pDef==0 ){ - no_such_func = 1; - }else{ - wrong_num_args = 1; - } - }else{ - is_agg = pDef->xFunc==0; - } - if( is_agg && !allowAgg ){ - sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId, zId); - nErr++; - is_agg = 0; - }else if( no_such_func ){ - sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); - nErr++; - }else if( wrong_num_args ){ - sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", - nId, zId); - nErr++; - } - if( is_agg ){ - pExpr->op = TK_AGG_FUNCTION; - if( pIsAgg ) *pIsAgg = 1; - } - for(i=0; nErr==0 && ipList->a[i].pExpr, - allowAgg && !is_agg, pIsAgg); - } - /* FIX ME: Compute pExpr->affinity based on the expected return - ** type of the function - */ - } - default: { - if( pExpr->pLeft ){ - nErr = sqlite3ExprCheck(pParse, pExpr->pLeft, allowAgg, pIsAgg); - } - if( nErr==0 && pExpr->pRight ){ - nErr = sqlite3ExprCheck(pParse, pExpr->pRight, allowAgg, pIsAgg); - } - if( nErr==0 && pExpr->pList ){ - int n = pExpr->pList->nExpr; - int i; - for(i=0; nErr==0 && ipList->a[i].pExpr; - nErr = sqlite3ExprCheck(pParse, pE2, allowAgg, pIsAgg); - } - } - break; - } - } - return nErr; -} - -/* -** Call sqlite3ExprResolveIds() followed by sqlite3ExprCheck(). -** -** This routine is provided as a convenience since it is very common -** to call ResolveIds() and Check() back to back. -*/ -int sqlite3ExprResolveAndCheck( - 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 *pIsAgg /* Set to TRUE if aggregates are found */ -){ - if( pExpr==0 ) return 0; - if( sqlite3ExprResolveIds(pParse,pSrcList,pEList,pExpr) ){ - return 1; - } - return sqlite3ExprCheck(pParse, pExpr, allowAgg, pIsAgg); +int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){ + walkExprTree(pExpr, codeSubqueryStep, pParse); + return 0; } /* @@ -1856,22 +1884,17 @@ static int appendAggInfo(Parse *pParse){ } /* -** Analyze the given expression looking for aggregate functions and -** for variables that need to be added to the pParse->aAgg[] array. -** Make additional entries to the pParse->aAgg[] array as necessary. +** This is an xFunc for walkExprTree() used to implement +** sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates +** for additional information. ** -** This routine should only be called after the expression has been -** analyzed by sqlite3ExprResolveIds() and sqlite3ExprCheck(). -** -** If errors are seen, leave an error message in zErrMsg and return -** the number of errors. +** This routine analyzes the aggregate function at pExpr. */ -int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ +static int analyzeAggregate(void *pArg, Expr *pExpr){ int i; AggExpr *aAgg; - int nErr = 0; + Parse *pParse = (Parse*)pArg; - if( pExpr==0 ) return 0; switch( pExpr->op ){ case TK_COLUMN: { aAgg = pParse->aAgg; @@ -1889,7 +1912,7 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ pParse->aAgg[i].pExpr = pExpr; } pExpr->iAgg = i; - break; + return 1; } case TK_AGG_FUNCTION: { aAgg = pParse->aAgg; @@ -1910,26 +1933,27 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); } pExpr->iAgg = i; - break; - } - default: { - if( pExpr->pLeft ){ - nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pLeft); - } - if( nErr==0 && pExpr->pRight ){ - nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pRight); - } - if( nErr==0 && pExpr->pList ){ - int n = pExpr->pList->nExpr; - int i; - for(i=0; nErr==0 && ipList->a[i].pExpr); - } - } - break; + return 1; } } - return nErr; + return 0; +} + +/* +** Analyze the given expression looking for aggregate functions and +** for variables that need to be added to the pParse->aAgg[] array. +** Make additional entries to the pParse->aAgg[] array as necessary. +** +** This routine should only be called after the expression has been +** analyzed by sqlite3ExprResolveNames(). +** +** If errors are seen, leave an error message in zErrMsg and return +** the number of errors. +*/ +int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ + int nErr = pParse->nErr; + walkExprTree(pExpr, analyzeAggregate, pParse); + return pParse->nErr - nErr; } /* diff --git a/src/insert.c b/src/insert.c index 156973162e..17b5cf8eee 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.130 2005/01/14 01:22:01 drh Exp $ +** $Id: insert.c,v 1.131 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" @@ -380,7 +380,7 @@ void sqlite3Insert( nColumn = pList->nExpr; dummy.nSrc = 0; for(i=0; ia[i].pExpr,0,0) ){ + if( sqlite3ExprResolveNames(pParse,&dummy,0,pList->a[i].pExpr,0,0,1) ){ goto insert_cleanup; } } diff --git a/src/select.c b/src/select.c index be8c578932..dce52c4022 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.222 2005/01/17 08:57:09 danielk1977 Exp $ +** $Id: select.c,v 1.223 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" @@ -2186,7 +2186,7 @@ static int processOrderGroupBy( sqlite3ExprDelete(pE); pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr); } - if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList, pE, isAgg, 0) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pE, isAgg, 0, 1) ){ return 1; } if( sqlite3ExprIsConstant(pE) ){ @@ -2355,12 +2355,12 @@ int sqlite3Select( ** Resolve the column names and do a semantics check on all the expressions. */ for(i=0; inExpr; i++){ - if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pEList->a[i].pExpr, - 1, &isAgg) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, 0, pEList->a[i].pExpr, + 1, &isAgg, 1) ){ goto select_end; } } - if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList, pWhere, 0, 0) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pWhere, 0, 0, 1) ){ goto select_end; } if( pHaving ){ @@ -2368,7 +2368,7 @@ int sqlite3Select( sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); goto select_end; } - if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList,pHaving,1,&isAgg) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, pEList,pHaving,1,&isAgg,1) ){ goto select_end; } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index de6cf04761..39393ea866 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.353 2005/01/13 02:14:25 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.354 2005/01/17 22:08:19 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -316,6 +316,7 @@ typedef struct KeyClass KeyClass; typedef struct CollSeq CollSeq; typedef struct KeyInfo KeyInfo; typedef struct SqlCursor SqlCursor; +typedef struct NameContext NameContext; typedef struct Fetch Fetch; typedef struct CursorSubst CursorSubst; @@ -814,6 +815,8 @@ struct Expr { ** The following are the meanings of bits in the Expr.flags field. */ #define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */ +#define EP_Agg 0x0002 /* Contains one or more aggregate functions */ +#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */ /* ** These macros can be used to test, set, or clear bits in the @@ -973,6 +976,8 @@ struct Select { ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ u8 isDistinct; /* True if the DISTINCT keyword is present */ + u8 isAgg; /* True if uses aggregate functions */ + u8 namesResolved; /* True if processed by sqlite3ExprResolve() */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -1250,6 +1255,38 @@ typedef struct { char **pzErrMsg; /* Error message stored here */ } InitData; +/* +** A NameContext defines a context in which to resolve table and column +** names. The context consists of a list of tables (the pSrcList) field and +** a list of named expression (pEList). The named expression list may +** be NULL. The pSrc corresponds to the FROM clause of a SELECT or +** to the table being operated on by INSERT, UPDATE, or DELETE. The +** pEList corresponds to the result set of a SELECT and is NULL for +** other statements. +** +** NameContexts can be nested. When resolving names, the inner-most +** context is searched first. If no match is found, the next outer +** context is checked. If there is still no match, the next context +** is checked. This process continues until either a match is found +** or all contexts are check. When a match is found, the nRef member of +** the context containing the match is incremented. +** +** Each subquery gets a new NameContext. The pNext field points to the +** NameContext in the parent query. Thus the process of scanning the +** NameContext list corresponds to searching through successively outer +** subqueries looking for a match. +*/ +struct NameContext { + Parse *pParse; /* The parser */ + SrcList *pSrcList; /* One or more tables used to resolve names */ + ExprList *pEList; /* Optional list of named expressions */ + int nRef; /* Number of names resolved by this context */ + int nErr; /* Number of errors encountered while resolving names */ + u8 allowAgg; /* Aggregate functions allowed here */ + u8 hasAgg; /* Expression actually contains aggregate functions */ + NameContext *pNext; /* Next outer name context. NULL for outermost */ +}; + /* ** Each SQL cursor (a cursor created by the DECLARE ... CURSOR syntax) ** is represented by an instance of the following structure. @@ -1386,8 +1423,8 @@ char *sqlite3NameFromToken(Token*); int sqlite3ExprCheck(Parse*, Expr*, int, int*); int sqlite3ExprCompare(Expr*, Expr*); int sqliteFuncId(Token*); -int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*); -int sqlite3ExprResolveAndCheck(Parse*,SrcList*,ExprList*,Expr*,int,int*); +int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, Expr*, int, int*, int); +int sqlite3ExprCodeSubquery(Parse*, Expr*); int sqlite3ExprAnalyzeAggregates(Parse*, Expr*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3Randomness(int, void*); diff --git a/src/trigger.c b/src/trigger.c index d4469bf1ad..0fe636971d 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -766,7 +766,7 @@ int sqlite3CodeRowTrigger( /* code the WHEN clause */ endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe); whenExpr = sqlite3ExprDup(pTrigger->pWhen); - if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){ + if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, whenExpr, 0, 0, 1)){ pParse->trigStack = trigStackEntry.pNext; sqlite3ExprDelete(whenExpr); return 1; diff --git a/src/update.c b/src/update.c index d3929984e9..38223ebae9 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.100 2004/12/25 01:03:14 drh Exp $ +** $Id: update.c,v 1.101 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" @@ -121,8 +121,8 @@ void sqlite3Update( */ chngRecno = 0; for(i=0; inExpr; i++){ - if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, - pChanges->a[i].pExpr, 0, 0) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, 0, + pChanges->a[i].pExpr, 0, 0, 1) ){ goto update_cleanup; } for(j=0; jnCol; j++){ @@ -198,7 +198,7 @@ void sqlite3Update( /* Resolve the column names in all the expressions in the ** WHERE clause. */ - if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){ + if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 0, 1) ){ goto update_cleanup; } diff --git a/src/where.c b/src/where.c index e035c06b01..118c8e90e9 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.128 2005/01/11 18:13:56 drh Exp $ +** $Id: where.c,v 1.129 2005/01/17 22:08:19 drh Exp $ */ #include "sqliteInt.h" @@ -181,9 +181,9 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){ ** tree. ** ** In order for this routine to work, the calling function must have -** previously invoked sqlite3ExprResolveIds() on the expression. See +** previously invoked sqlite3ExprResolveNames() on the expression. See ** the header comment on that routine for additional information. -** The sqlite3ExprResolveIds() routines looks for column names and +** The sqlite3ExprResolveNames() routines looks for column names and ** sets their opcodes to TK_COLUMN and their Expr.iTable fields to ** the VDBE cursor number of the table. */