mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Infrastructure changes to handle name resolution differently. This is needed
to fix various long-standing problems with column names in joins. It will also make the implementation of correlated subqueries easier. (CVS 2228) FossilOrigin-Name: 4a7534396a72ccb300303df28798bb2c50293782
This commit is contained in:
30
manifest
30
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)
|
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-17T08:57:09
|
D 2005-01-17T22:08:19
|
||||||
F Makefile.in 78d6d0af3725aef32468ac9923444d7645d21a28
|
F Makefile.in 78d6d0af3725aef32468ac9923444d7645d21a28
|
||||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||||
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
||||||
@@ -31,15 +31,15 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
|
|||||||
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
|
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
|
||||||
F src/btree.c 97101cce85304edbaedafc5f39ab12e2dc78b076
|
F src/btree.c 97101cce85304edbaedafc5f39ab12e2dc78b076
|
||||||
F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497
|
F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497
|
||||||
F src/build.c 07d50fe1b167c77f183aedd59362d55e1f579163
|
F src/build.c 4638b87f5e797e364ff995f8338b281b61dd8be1
|
||||||
F src/cursor.c f883813759742068890b1f699335872bfa8fdf41
|
F src/cursor.c f883813759742068890b1f699335872bfa8fdf41
|
||||||
F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
|
F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
|
||||||
F src/delete.c 32277d2834e36c7538c047f14d643751c256c73b
|
F src/delete.c 5872f452031f31c6941ef70e9f4e1823e9fecefc
|
||||||
F src/expr.c 22bc51e18b2e686f3c831d33b2c38b5a3e6733f9
|
F src/expr.c 2a9485be4ec44eea0f3eada89f415f2172fc5c2e
|
||||||
F src/func.c dc188d862d7276ea897655b248e2cb17022686e3
|
F src/func.c dc188d862d7276ea897655b248e2cb17022686e3
|
||||||
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
||||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||||
F src/insert.c 2a8fadfd7494881632fcae453f115d42a7a58dee
|
F src/insert.c 0acf8a8cd21d60c60432c0004586d2aee0ad8d8e
|
||||||
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
||||||
F src/main.c cbe5a05baabad9fabb733065d0fb00c0b36f6ef1
|
F src/main.c cbe5a05baabad9fabb733065d0fb00c0b36f6ef1
|
||||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||||
@@ -57,10 +57,10 @@ F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1
|
|||||||
F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec
|
F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec
|
||||||
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
||||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||||
F src/select.c f74bdde6e77e7c351084646edbc859b08e0a3414
|
F src/select.c cfd5f30611967ebd7c39d4bd448a1b1e263e9fb8
|
||||||
F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770
|
F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770
|
||||||
F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611
|
F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611
|
||||||
F src/sqliteInt.h 641b348a109a080262d9f3603f2e94143d4383f2
|
F src/sqliteInt.h f7ed4e6e112df9af7c85600bfb3b0af02e7b7577
|
||||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||||
F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b
|
F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b
|
||||||
F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793
|
F src/test1.c 2e27b110ba5aa16977bad1cc2388553479d73793
|
||||||
@@ -69,8 +69,8 @@ F src/test3.c a72f20066cccd5a7b9f20b7b78fa9b05b47b3020
|
|||||||
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
|
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
|
||||||
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
|
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
|
||||||
F src/tokenize.c c1d124ec41422c9ec14360ea3a1f98ca4acf7cf1
|
F src/tokenize.c c1d124ec41422c9ec14360ea3a1f98ca4acf7cf1
|
||||||
F src/trigger.c 98f3b07c08ba01b34cff139ef9687883d325ae8e
|
F src/trigger.c 210fe50d4b3c01d3e5f8ef8a7a820117416a992b
|
||||||
F src/update.c 0979397c41ac29c54fe0cc687a356d8629a633af
|
F src/update.c 79a1511104963df3368d9235f9393cfe7f38c027
|
||||||
F src/utf.c 9bece2c7b94d9002ab1bb900a7658c6f826b0f74
|
F src/utf.c 9bece2c7b94d9002ab1bb900a7658c6f826b0f74
|
||||||
F src/util.c 63e8d77659df88b292ac2a9dbd4766419b0ea158
|
F src/util.c 63e8d77659df88b292ac2a9dbd4766419b0ea158
|
||||||
F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203
|
F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203
|
||||||
@@ -80,7 +80,7 @@ F src/vdbeInt.h f2b5f54d9881bbc89fff02d95f3f825ade68bce2
|
|||||||
F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd
|
F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd
|
||||||
F src/vdbeaux.c 6c294f7390880a7bb4795c9e0bc605b1a416579a
|
F src/vdbeaux.c 6c294f7390880a7bb4795c9e0bc605b1a416579a
|
||||||
F src/vdbemem.c 62fe89471b656a922e9879be005abf690509ead3
|
F src/vdbemem.c 62fe89471b656a922e9879be005abf690509ead3
|
||||||
F src/where.c 3a0d08505e298242f6f151f019a05129a4f8704c
|
F src/where.c 09defb7d1efb150d323fc253c6534d23e8a73ce6
|
||||||
F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432
|
F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432
|
||||||
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
||||||
F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a
|
F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a
|
||||||
@@ -269,7 +269,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
|
|||||||
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
||||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||||
F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746
|
F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746
|
||||||
P 6244252915fa312a6c4d192464023d95aaef4661
|
P 5a9da62ae303800ded99942aed30eadeb3863da3
|
||||||
R 8fdfbf5efd695da44259ce4a14c6dc0d
|
R 27952fc035e1cac4b0d3a414cfc9fe27
|
||||||
U danielk1977
|
U drh
|
||||||
Z f3732671f0bcdc732596f3a051a6bbad
|
Z 916e3799f439fba92eda7a2a24dc2de5
|
||||||
|
@@ -1 +1 @@
|
|||||||
5a9da62ae303800ded99942aed30eadeb3863da3
|
4a7534396a72ccb300303df28798bb2c50293782
|
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -884,7 +884,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
|
|||||||
}else{
|
}else{
|
||||||
sqlite3ExprDelete(pCol->pDflt);
|
sqlite3ExprDelete(pCol->pDflt);
|
||||||
pCol->pDflt = sqlite3ExprDup(pExpr);
|
pCol->pDflt = sqlite3ExprDup(pExpr);
|
||||||
sqlite3ExprCheck(pParse, pExpr, 0, 0);
|
sqlite3ExprResolveNames(pParse,0,0,pExpr,0,0,0);
|
||||||
}
|
}
|
||||||
sqlite3ExprDelete(pExpr);
|
sqlite3ExprDelete(pExpr);
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ void sqlite3DeleteFrom(
|
|||||||
*/
|
*/
|
||||||
assert( pTabList->nSrc==1 );
|
assert( pTabList->nSrc==1 );
|
||||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
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;
|
goto delete_from_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
830
src/expr.c
830
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -62,8 +62,8 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** pExpr is the left operand of a comparison operator. aff2 is the
|
** pExpr is an operand of a comparison operator. aff2 is the
|
||||||
** type affinity of the right operand. This routine returns the
|
** type affinity of the other operand. This routine returns the
|
||||||
** type affinity that should be used for the comparison operator.
|
** type affinity that should be used for the comparison operator.
|
||||||
*/
|
*/
|
||||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||||
@@ -560,6 +560,59 @@ void sqlite3ExprListDelete(ExprList *pList){
|
|||||||
sqliteFree(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
|
** Walk an expression tree. Return 1 if the expression is constant
|
||||||
** and 0 if it involves variables.
|
** and 0 if it involves variables.
|
||||||
@@ -569,35 +622,9 @@ void sqlite3ExprListDelete(ExprList *pList){
|
|||||||
** a constant.
|
** a constant.
|
||||||
*/
|
*/
|
||||||
int sqlite3ExprIsConstant(Expr *p){
|
int sqlite3ExprIsConstant(Expr *p){
|
||||||
switch( p->op ){
|
int isConst = 1;
|
||||||
case TK_ID:
|
walkExprTree(p, exprNodeIsConstant, &isConst);
|
||||||
case TK_COLUMN:
|
return isConst;
|
||||||
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; i<p->pList->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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -670,8 +697,7 @@ static int lookupName(
|
|||||||
Token *pDbToken, /* Name of the database containing table, or NULL */
|
Token *pDbToken, /* Name of the database containing table, or NULL */
|
||||||
Token *pTableToken, /* Name of table containing column, or NULL */
|
Token *pTableToken, /* Name of table containing column, or NULL */
|
||||||
Token *pColumnToken, /* Name of the column. */
|
Token *pColumnToken, /* Name of the column. */
|
||||||
SrcList *pSrcList, /* List of tables used to resolve column names */
|
NameContext *pNC, /* The name context used to resolve the name */
|
||||||
ExprList *pEList, /* List of expressions used to resolve "AS" */
|
|
||||||
Expr *pExpr /* Make this EXPR node point to the selected column */
|
Expr *pExpr /* Make this EXPR node point to the selected column */
|
||||||
){
|
){
|
||||||
char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */
|
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 i, j; /* Loop counters */
|
||||||
int cnt = 0; /* Number of matching column names */
|
int cnt = 0; /* Number of matching column names */
|
||||||
int cntTab = 0; /* Number of matching table 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 *pItem; /* Use for looping over pSrcList items */
|
||||||
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
|
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
|
||||||
|
|
||||||
@@ -691,73 +717,44 @@ static int lookupName(
|
|||||||
if( sqlite3_malloc_failed ){
|
if( sqlite3_malloc_failed ){
|
||||||
return 1; /* Leak memory (zDb and zTab) if malloc fails */
|
return 1; /* Leak memory (zDb and zTab) if malloc fails */
|
||||||
}
|
}
|
||||||
assert( zTab==0 || pEList==0 );
|
|
||||||
|
|
||||||
pExpr->iTable = -1;
|
pExpr->iTable = -1;
|
||||||
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
while( pNC && cnt==0 ){
|
||||||
Table *pTab = pItem->pTab;
|
SrcList *pSrcList = pNC->pSrcList;
|
||||||
Column *pCol;
|
ExprList *pEList = pNC->pEList;
|
||||||
|
|
||||||
if( pTab==0 ) continue;
|
pNC->nRef++;
|
||||||
assert( pTab->nCol>0 );
|
/* assert( zTab==0 || pEList==0 ); */
|
||||||
if( zTab ){
|
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
||||||
if( pItem->zAlias ){
|
Table *pTab = pItem->pTab;
|
||||||
char *zTabName = pItem->zAlias;
|
Column *pCol;
|
||||||
if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
|
|
||||||
}else{
|
if( pTab==0 ) continue;
|
||||||
char *zTabName = pTab->zName;
|
assert( pTab->nCol>0 );
|
||||||
if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
|
if( zTab ){
|
||||||
if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
|
if( pItem->zAlias ){
|
||||||
continue;
|
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++) ){
|
||||||
if( 0==(cntTab++) ){
|
|
||||||
pExpr->iTable = pItem->iCursor;
|
|
||||||
pExpr->iDb = pTab->iDb;
|
|
||||||
pMatch = pItem;
|
|
||||||
}
|
|
||||||
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
|
||||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
|
||||||
cnt++;
|
|
||||||
pExpr->iTable = pItem->iCursor;
|
pExpr->iTable = pItem->iCursor;
|
||||||
pMatch = pItem;
|
|
||||||
pExpr->iDb = pTab->iDb;
|
pExpr->iDb = pTab->iDb;
|
||||||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
pMatch = pItem;
|
||||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
|
||||||
pExpr->affinity = pTab->aCol[j].affinity;
|
|
||||||
pExpr->pColl = pTab->aCol[j].pColl;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
||||||
}
|
|
||||||
|
|
||||||
#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 ){
|
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||||
cnt++;
|
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->iColumn = j==pTab->iPKey ? -1 : j;
|
||||||
pExpr->affinity = pTab->aCol[j].affinity;
|
pExpr->affinity = pTab->aCol[j].affinity;
|
||||||
pExpr->pColl = pTab->aCol[j].pColl;
|
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) */
|
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Perhaps the name is a reference to the ROWID
|
** Perhaps the name is a reference to the ROWID
|
||||||
*/
|
*/
|
||||||
if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
|
if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
|
||||||
cnt = 1;
|
cnt = 1;
|
||||||
pExpr->iColumn = -1;
|
pExpr->iColumn = -1;
|
||||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z
|
** 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
|
** might refer to an result-set alias. This happens, for example, when
|
||||||
** we are resolving names in the WHERE clause of the following command:
|
** we are resolving names in the WHERE clause of the following command:
|
||||||
**
|
**
|
||||||
** SELECT a+b AS x FROM table WHERE x<10;
|
** SELECT a+b AS x FROM table WHERE x<10;
|
||||||
**
|
**
|
||||||
** In cases like this, replace pExpr with a copy of the expression that
|
** 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.
|
** 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
|
** Note that the expression in the result set should have already been
|
||||||
** resolved by the time the WHERE clause is resolved.
|
** resolved by the time the WHERE clause is resolved.
|
||||||
*/
|
*/
|
||||||
if( cnt==0 && pEList!=0 ){
|
if( cnt==0 && pEList!=0 ){
|
||||||
for(j=0; j<pEList->nExpr; j++){
|
for(j=0; j<pEList->nExpr; j++){
|
||||||
char *zAs = pEList->a[j].zName;
|
char *zAs = pEList->a[j].zName;
|
||||||
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
||||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||||
pExpr->op = TK_AS;
|
pExpr->op = TK_AS;
|
||||||
pExpr->iColumn = j;
|
pExpr->iColumn = j;
|
||||||
pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr);
|
pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr);
|
||||||
sqliteFree(zCol);
|
sqliteFree(zCol);
|
||||||
assert( zTab==0 && zDb==0 );
|
assert( zTab==0 && zDb==0 );
|
||||||
return 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);
|
sqlite3ExprDelete(pExpr->pRight);
|
||||||
pExpr->pRight = 0;
|
pExpr->pRight = 0;
|
||||||
pExpr->op = TK_COLUMN;
|
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;
|
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; i<pSrcList->nSrc; i++){
|
||||||
|
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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 && i<n; i++){
|
||||||
|
walkExprTree(pList->a[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
|
** This routine walks an expression tree and resolves references to
|
||||||
** table columns. Nodes of the form ID.ID or ID resolve into an
|
** 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
|
** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an
|
||||||
** alias for ROWID.
|
** alias for ROWID.
|
||||||
**
|
**
|
||||||
** We also check for instances of the IN operator. IN comes in two
|
** Also resolve function names and check the functions for proper
|
||||||
** forms:
|
** 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)
|
** expr IN (exprlist)
|
||||||
** and
|
** and
|
||||||
@@ -891,76 +1150,18 @@ static int lookupName(
|
|||||||
** This routine also looks for scalar SELECTs that are part of an expression.
|
** 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
|
** If it finds any, it generates code to write the value of that select
|
||||||
** into a memory cell.
|
** 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(
|
static int codeSubqueryStep(void *pArg, Expr *pExpr){
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse = (Parse*)pArg;
|
||||||
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;
|
|
||||||
|
|
||||||
if( pExpr==0 || pSrcList==0 ) return 0;
|
|
||||||
for(i=0; i<pSrcList->nSrc; i++){
|
|
||||||
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab );
|
|
||||||
}
|
|
||||||
switch( pExpr->op ){
|
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: {
|
case TK_IN: {
|
||||||
char affinity;
|
char affinity;
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
KeyInfo keyInfo;
|
KeyInfo keyInfo;
|
||||||
int addr; /* Address of OP_OpenTemp instruction */
|
int addr; /* Address of OP_OpenTemp instruction */
|
||||||
|
|
||||||
if( v==0 ) return 1;
|
if( v==0 ) return 2;
|
||||||
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
affinity = sqlite3ExprAffinity(pExpr->pLeft);
|
affinity = sqlite3ExprAffinity(pExpr->pLeft);
|
||||||
|
|
||||||
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
||||||
@@ -1019,10 +1220,10 @@ int sqlite3ExprResolveIds(
|
|||||||
if( !sqlite3ExprIsConstant(pE2) ){
|
if( !sqlite3ExprIsConstant(pE2) ){
|
||||||
sqlite3ErrorMsg(pParse,
|
sqlite3ErrorMsg(pParse,
|
||||||
"right-hand side of IN operator must be constant");
|
"right-hand side of IN operator must be constant");
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
if( sqlite3ExprCheck(pParse, pE2, 0, 0) ){
|
if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0, 0) ){
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the expression and insert it into the temp table */
|
/* Evaluate the expression and insert it into the temp table */
|
||||||
@@ -1033,8 +1234,7 @@ int sqlite3ExprResolveIds(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
|
sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
|
||||||
|
return 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TK_SELECT: {
|
case TK_SELECT: {
|
||||||
@@ -1043,191 +1243,19 @@ int sqlite3ExprResolveIds(
|
|||||||
** of the memory cell in iColumn.
|
** of the memory cell in iColumn.
|
||||||
*/
|
*/
|
||||||
pExpr->iColumn = pParse->nMem++;
|
pExpr->iColumn = pParse->nMem++;
|
||||||
if(sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0)){
|
sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0);
|
||||||
return 1;
|
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; i<pList->nExpr; i++){
|
|
||||||
Expr *pArg = pList->a[i].pExpr;
|
|
||||||
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pArg) ){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** pExpr is a node that defines a function of some kind. It might
|
** Generate code to evaluate subqueries and IN operators.
|
||||||
** 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){
|
int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){
|
||||||
switch( pExpr->op ){
|
walkExprTree(pExpr, codeSubqueryStep, pParse);
|
||||||
case TK_FUNCTION: {
|
return 0;
|
||||||
*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 && i<n; i++){
|
|
||||||
nErr = sqlite3ExprCheck(pParse, pExpr->pList->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 && i<n; i++){
|
|
||||||
Expr *pE2 = pExpr->pList->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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1856,22 +1884,17 @@ static int appendAggInfo(Parse *pParse){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Analyze the given expression looking for aggregate functions and
|
** This is an xFunc for walkExprTree() used to implement
|
||||||
** for variables that need to be added to the pParse->aAgg[] array.
|
** sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates
|
||||||
** Make additional entries to the pParse->aAgg[] array as necessary.
|
** for additional information.
|
||||||
**
|
**
|
||||||
** This routine should only be called after the expression has been
|
** This routine analyzes the aggregate function at pExpr.
|
||||||
** analyzed by sqlite3ExprResolveIds() and sqlite3ExprCheck().
|
|
||||||
**
|
|
||||||
** If errors are seen, leave an error message in zErrMsg and return
|
|
||||||
** the number of errors.
|
|
||||||
*/
|
*/
|
||||||
int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
|
static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||||
int i;
|
int i;
|
||||||
AggExpr *aAgg;
|
AggExpr *aAgg;
|
||||||
int nErr = 0;
|
Parse *pParse = (Parse*)pArg;
|
||||||
|
|
||||||
if( pExpr==0 ) return 0;
|
|
||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
case TK_COLUMN: {
|
case TK_COLUMN: {
|
||||||
aAgg = pParse->aAgg;
|
aAgg = pParse->aAgg;
|
||||||
@@ -1889,7 +1912,7 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
|
|||||||
pParse->aAgg[i].pExpr = pExpr;
|
pParse->aAgg[i].pExpr = pExpr;
|
||||||
}
|
}
|
||||||
pExpr->iAgg = i;
|
pExpr->iAgg = i;
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
case TK_AGG_FUNCTION: {
|
case TK_AGG_FUNCTION: {
|
||||||
aAgg = pParse->aAgg;
|
aAgg = pParse->aAgg;
|
||||||
@@ -1910,26 +1933,27 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
|
|||||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||||
}
|
}
|
||||||
pExpr->iAgg = i;
|
pExpr->iAgg = i;
|
||||||
break;
|
return 1;
|
||||||
}
|
|
||||||
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 && i<n; i++){
|
|
||||||
nErr = sqlite3ExprAnalyzeAggregates(pParse, pExpr->pList->a[i].pExpr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -380,7 +380,7 @@ void sqlite3Insert(
|
|||||||
nColumn = pList->nExpr;
|
nColumn = pList->nExpr;
|
||||||
dummy.nSrc = 0;
|
dummy.nSrc = 0;
|
||||||
for(i=0; i<nColumn; i++){
|
for(i=0; i<nColumn; i++){
|
||||||
if( sqlite3ExprResolveAndCheck(pParse,&dummy,0,pList->a[i].pExpr,0,0) ){
|
if( sqlite3ExprResolveNames(pParse,&dummy,0,pList->a[i].pExpr,0,0,1) ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
src/select.c
12
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -2186,7 +2186,7 @@ static int processOrderGroupBy(
|
|||||||
sqlite3ExprDelete(pE);
|
sqlite3ExprDelete(pE);
|
||||||
pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
if( sqlite3ExprIsConstant(pE) ){
|
if( sqlite3ExprIsConstant(pE) ){
|
||||||
@@ -2355,12 +2355,12 @@ int sqlite3Select(
|
|||||||
** Resolve the column names and do a semantics check on all the expressions.
|
** Resolve the column names and do a semantics check on all the expressions.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pEList->nExpr; i++){
|
for(i=0; i<pEList->nExpr; i++){
|
||||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pEList->a[i].pExpr,
|
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pEList->a[i].pExpr,
|
||||||
1, &isAgg) ){
|
1, &isAgg, 1) ){
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList, pWhere, 0, 0) ){
|
if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pWhere, 0, 0, 1) ){
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
if( pHaving ){
|
if( pHaving ){
|
||||||
@@ -2368,7 +2368,7 @@ int sqlite3Select(
|
|||||||
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
|
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, pEList,pHaving,1,&isAgg) ){
|
if( sqlite3ExprResolveNames(pParse, pTabList, pEList,pHaving,1,&isAgg,1) ){
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** 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_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -316,6 +316,7 @@ typedef struct KeyClass KeyClass;
|
|||||||
typedef struct CollSeq CollSeq;
|
typedef struct CollSeq CollSeq;
|
||||||
typedef struct KeyInfo KeyInfo;
|
typedef struct KeyInfo KeyInfo;
|
||||||
typedef struct SqlCursor SqlCursor;
|
typedef struct SqlCursor SqlCursor;
|
||||||
|
typedef struct NameContext NameContext;
|
||||||
typedef struct Fetch Fetch;
|
typedef struct Fetch Fetch;
|
||||||
typedef struct CursorSubst CursorSubst;
|
typedef struct CursorSubst CursorSubst;
|
||||||
|
|
||||||
@@ -814,6 +815,8 @@ struct Expr {
|
|||||||
** The following are the meanings of bits in the Expr.flags field.
|
** 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_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
|
** 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 */
|
ExprList *pEList; /* The fields of the result */
|
||||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||||
u8 isDistinct; /* True if the DISTINCT keyword is present */
|
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 */
|
SrcList *pSrc; /* The FROM clause */
|
||||||
Expr *pWhere; /* The WHERE clause */
|
Expr *pWhere; /* The WHERE clause */
|
||||||
ExprList *pGroupBy; /* The GROUP BY clause */
|
ExprList *pGroupBy; /* The GROUP BY clause */
|
||||||
@@ -1250,6 +1255,38 @@ typedef struct {
|
|||||||
char **pzErrMsg; /* Error message stored here */
|
char **pzErrMsg; /* Error message stored here */
|
||||||
} InitData;
|
} 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)
|
** Each SQL cursor (a cursor created by the DECLARE ... CURSOR syntax)
|
||||||
** is represented by an instance of the following structure.
|
** is represented by an instance of the following structure.
|
||||||
@@ -1386,8 +1423,8 @@ char *sqlite3NameFromToken(Token*);
|
|||||||
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||||
int sqlite3ExprCompare(Expr*, Expr*);
|
int sqlite3ExprCompare(Expr*, Expr*);
|
||||||
int sqliteFuncId(Token*);
|
int sqliteFuncId(Token*);
|
||||||
int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
|
int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, Expr*, int, int*, int);
|
||||||
int sqlite3ExprResolveAndCheck(Parse*,SrcList*,ExprList*,Expr*,int,int*);
|
int sqlite3ExprCodeSubquery(Parse*, Expr*);
|
||||||
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
|
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
|
||||||
Vdbe *sqlite3GetVdbe(Parse*);
|
Vdbe *sqlite3GetVdbe(Parse*);
|
||||||
void sqlite3Randomness(int, void*);
|
void sqlite3Randomness(int, void*);
|
||||||
|
@@ -766,7 +766,7 @@ int sqlite3CodeRowTrigger(
|
|||||||
/* code the WHEN clause */
|
/* code the WHEN clause */
|
||||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||||
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
||||||
if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
|
if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, whenExpr, 0, 0, 1)){
|
||||||
pParse->trigStack = trigStackEntry.pNext;
|
pParse->trigStack = trigStackEntry.pNext;
|
||||||
sqlite3ExprDelete(whenExpr);
|
sqlite3ExprDelete(whenExpr);
|
||||||
return 1;
|
return 1;
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -121,8 +121,8 @@ void sqlite3Update(
|
|||||||
*/
|
*/
|
||||||
chngRecno = 0;
|
chngRecno = 0;
|
||||||
for(i=0; i<pChanges->nExpr; i++){
|
for(i=0; i<pChanges->nExpr; i++){
|
||||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
|
if( sqlite3ExprResolveNames(pParse, pTabList, 0,
|
||||||
pChanges->a[i].pExpr, 0, 0) ){
|
pChanges->a[i].pExpr, 0, 0, 1) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
}
|
}
|
||||||
for(j=0; j<pTab->nCol; j++){
|
for(j=0; j<pTab->nCol; j++){
|
||||||
@@ -198,7 +198,7 @@ void sqlite3Update(
|
|||||||
/* Resolve the column names in all the expressions in the
|
/* Resolve the column names in all the expressions in the
|
||||||
** WHERE clause.
|
** WHERE clause.
|
||||||
*/
|
*/
|
||||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
|
if( sqlite3ExprResolveNames(pParse, pTabList, 0, pWhere, 0, 0, 1) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -181,9 +181,9 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
|
|||||||
** tree.
|
** tree.
|
||||||
**
|
**
|
||||||
** In order for this routine to work, the calling function must have
|
** 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 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
|
** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
|
||||||
** the VDBE cursor number of the table.
|
** the VDBE cursor number of the table.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user