1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Fix some problems to do with WITH clauses and name resolution.

FossilOrigin-Name: 6a549187ed8b5ed50daefa676ff666ae2ed43346
This commit is contained in:
dan
2014-01-17 14:59:27 +00:00
parent 2d4dc5fc60
commit b290f11775
8 changed files with 121 additions and 64 deletions

View File

@@ -1,5 +1,5 @@
C Remove\ssome\scode\sfrom\sresolve.c\sthat\swas\sonly\srequired\sfor\srecursive\scte\sreferences\sin\ssub-queries.\sAlso\sa\sstray\s"finish_test"\scommand\sin\spagerfault.test. C Fix\ssome\sproblems\sto\sdo\swith\sWITH\sclauses\sand\sname\sresolution.
D 2014-01-17T11:48:24.294 D 2014-01-17T14:59:27.898
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -209,7 +209,7 @@ F src/os_unix.c 3a4dcb554d3c915075766162f28c3fd4cdb75968
F src/os_win.c 1b21af72c5fa6f9e519a5fcab33e80d182b1aedb F src/os_win.c 1b21af72c5fa6f9e519a5fcab33e80d182b1aedb
F src/pager.c efa923693e958696eee69b205a20bfbc402c8480 F src/pager.c efa923693e958696eee69b205a20bfbc402c8480
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 824eeb752c026b551bda2b66163889d7664b42e4 F src/parse.y 475896cb883bbf4782e98abda42efbbdcbdb75f5
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b
@@ -219,12 +219,12 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6 F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 65c13f22edfd6af04829439955c7cf5749ea4e87 F src/select.c c77955f93121adc8b4b43a98add62fbaa2b48132
F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48 F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h d49c0bea5282f15c1eb1eb9d705770f70d19c1e2 F src/sqliteInt.h 9600eeb486c274fbdb815d040e4a7f262b7317e1
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -274,7 +274,7 @@ F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9 F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78 F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 7dc42e9beb8c3263b79d10c195b3f5264b5f874a F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98 F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98
F src/update.c c2706a6eb232a96345c35b7e1e75a188e26812bb F src/update.c c2706a6eb232a96345c35b7e1e75a188e26812bb
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
@@ -292,7 +292,7 @@ F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c 369b0259fabfb22644d197736ae622f762cbaba8 F src/where.c 369b0259fabfb22644d197736ae622f762cbaba8
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358 F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1092,6 +1092,7 @@ F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/with1.test 90490c75e98e1914d84b7cef9e636b48917a020f F test/with1.test 90490c75e98e1914d84b7cef9e636b48917a020f
F test/with2.test 790c4b7ab3f4eb6984a3bbdae8d4ab429ebe9259
F test/withM.test 52448ce23e1c2ecba79d10e130ee49ce9f9a2a7a F test/withM.test 52448ce23e1c2ecba79d10e130ee49ce9f9a2a7a
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8 F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
@@ -1150,7 +1151,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 9efc120a1548c03f3d8aabbadf1050ff2a119c31 P f68c6c4d36481526a9348244adc571ea282dc9eb
R 175ad2c9f66168be6fabd0b7fdb44bd2 R d73fd639096ae3d6dc6dd6a7018ffc11
U dan U dan
Z 6e3919f2cc39eeea18a32475675bdfc0 Z 6339477b00dd8c67441747d0ac03cfea

View File

@@ -1 +1 @@
f68c6c4d36481526a9348244adc571ea282dc9eb 6a549187ed8b5ed50daefa676ff666ae2ed43346

View File

@@ -661,7 +661,7 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W) cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). { orderby_opt(O) limit_opt(L). {
sqlite3WithPush(pParse,C); sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE"); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE");
sqlite3DeleteFrom(pParse,X,W); sqlite3DeleteFrom(pParse,X,W);
@@ -669,7 +669,7 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W)
%endif %endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). { cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
sqlite3WithPush(pParse,C); sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3DeleteFrom(pParse,X,W); sqlite3DeleteFrom(pParse,X,W);
} }
@@ -686,7 +686,7 @@ where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W) orderby_opt(O) limit_opt(L). { where_opt(W) orderby_opt(O) limit_opt(L). {
sqlite3WithPush(pParse, C); sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3ExprListCheckLength(pParse,Y,"set list");
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE"); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
@@ -696,7 +696,7 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W). { where_opt(W). {
sqlite3WithPush(pParse, C); sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3ExprListCheckLength(pParse,Y,"set list");
sqlite3Update(pParse,X,Y,W,R); sqlite3Update(pParse,X,Y,W,R);
@@ -718,12 +718,12 @@ setlist(A) ::= nm(X) EQ expr(Y). {
////////////////////////// The INSERT command ///////////////////////////////// ////////////////////////// The INSERT command /////////////////////////////////
// //
cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). { cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). {
sqlite3WithPush(pParse, W); sqlite3WithPush(pParse, W, 1);
sqlite3Insert(pParse, X, S, F, R); sqlite3Insert(pParse, X, S, F, R);
} }
cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES. cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
{ {
sqlite3WithPush(pParse, W); sqlite3WithPush(pParse, W, 1);
sqlite3Insert(pParse, X, 0, F, R); sqlite3Insert(pParse, X, 0, F, R);
} }

View File

@@ -3527,12 +3527,19 @@ static struct Cte *searchWith(With *pWith, struct SrcList_item *pItem){
/* The code generator maintains a stack of active WITH clauses /* The code generator maintains a stack of active WITH clauses
** with the inner-most WITH clause being at the top of the stack. ** with the inner-most WITH clause being at the top of the stack.
** **
** These routines push and pull WITH clauses on the stack. ** This routine pushes the WITH clause passed as the second argument
** onto the top of the stack. If argument bFree is true, then this
** WITH clause will never be popped from the stack. In this case it
** should be freed along with the Parse object. In other cases, when
** bFree==0, the With object will be freed along with the SELECT
** statement with which it is associated.
*/ */
void sqlite3WithPush(Parse *pParse, With *pWith){ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
assert( bFree==0 || pParse->pWith==0 );
if( pWith ){ if( pWith ){
pWith->pOuter = pParse->pWith; pWith->pOuter = pParse->pWith;
pParse->pWith = pWith; pParse->pWith = pWith;
pParse->bFreeWith = bFree;
} }
} }
@@ -3649,6 +3656,19 @@ static int withExpand(
} }
#endif #endif
#ifndef SQLITE_OMIT_CTE
static void selectPopWith(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
if( p->pWith ){
assert( pParse->pWith==p->pWith );
pParse->pWith = p->pWith->pOuter;
}
return WRC_Continue;
}
#else
#define selectPopWith 0
#endif
/* /*
** This routine is a Walker callback for "expanding" a SELECT statement. ** This routine is a Walker callback for "expanding" a SELECT statement.
** "Expanding" means to do the following: ** "Expanding" means to do the following:
@@ -3692,6 +3712,7 @@ static int selectExpander(Walker *pWalker, Select *p){
} }
pTabList = p->pSrc; pTabList = p->pSrc;
pEList = p->pEList; pEList = p->pEList;
sqlite3WithPush(pParse, p->pWith, 0);
/* Make sure cursor numbers have been assigned to all entries in /* Make sure cursor numbers have been assigned to all entries in
** the FROM clause of the SELECT statement. ** the FROM clause of the SELECT statement.
@@ -3710,6 +3731,9 @@ static int selectExpander(Walker *pWalker, Select *p){
/* This statement has already been prepared. There is no need /* This statement has already been prepared. There is no need
** to go further. */ ** to go further. */
assert( i==0 ); assert( i==0 );
#ifndef SQLITE_OMIT_CTE
selectPopWith(pWalker, p);
#endif
return WRC_Prune; return WRC_Prune;
} }
#ifndef SQLITE_OMIT_CTE #ifndef SQLITE_OMIT_CTE
@@ -3941,30 +3965,6 @@ static int selectExpander(Walker *pWalker, Select *p){
return WRC_Continue; return WRC_Continue;
} }
/*
** Function (or macro) selectExpanderWith is used as the SELECT callback
** by sqlite3SelectExpand(). In builds that do not support CTEs, this
** is equivalent to the selectExpander() function. In CTE-enabled builds,
** any WITH clause associated with the SELECT statement needs to be
** pushed onto the stack before calling selectExpander(), and popped
** off again afterwards.
*/
#ifndef SQLITE_OMIT_CTE
static int selectExpanderWith(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
int res;
sqlite3WithPush(pParse, p->pWith);
res = selectExpander(pWalker, p);
if( p->pWith ){
assert( pParse->pWith==p->pWith );
pParse->pWith = p->pWith->pOuter;
}
return res;
}
#else
#define selectExpanderWith selectExpander
#endif
/* /*
** No-op routine for the parse-tree walker. ** No-op routine for the parse-tree walker.
** **
@@ -4001,7 +4001,8 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback = convertCompoundSelectToSubquery;
sqlite3WalkSelect(&w, pSelect); sqlite3WalkSelect(&w, pSelect);
} }
w.xSelectCallback = selectExpanderWith; w.xSelectCallback = selectExpander;
w.xSelectCallback2 = selectPopWith;
sqlite3WalkSelect(&w, pSelect); sqlite3WalkSelect(&w, pSelect);
} }
@@ -4020,7 +4021,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
** at that point because identifiers had not yet been resolved. This ** at that point because identifiers had not yet been resolved. This
** routine is called after identifier resolution. ** routine is called after identifier resolution.
*/ */
static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Parse *pParse; Parse *pParse;
int i; int i;
SrcList *pTabList; SrcList *pTabList;
@@ -4043,7 +4044,6 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
} }
} }
} }
return WRC_Continue;
} }
#endif #endif
@@ -4059,10 +4059,9 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
Walker w; Walker w;
memset(&w, 0, sizeof(w)); memset(&w, 0, sizeof(w));
w.xSelectCallback = selectAddSubqueryTypeInfo; w.xSelectCallback2 = selectAddSubqueryTypeInfo;
w.xExprCallback = exprWalkNoop; w.xExprCallback = exprWalkNoop;
w.pParse = pParse; w.pParse = pParse;
w.bSelectDepthFirst = 1;
sqlite3WalkSelect(&w, pSelect); sqlite3WalkSelect(&w, pSelect);
#endif #endif
} }

View File

@@ -2371,6 +2371,7 @@ struct Parse {
Table *pZombieTab; /* List of Table objects to delete after code gen */ Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
With *pWith; /* Current WITH clause, or NULL */ With *pWith; /* Current WITH clause, or NULL */
u8 bFreeWith; /* True if pWith should be freed with parser */
}; };
/* /*
@@ -2612,9 +2613,9 @@ struct Sqlite3Config {
struct Walker { struct Walker {
int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
Parse *pParse; /* Parser context. */ Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */ int walkerDepth; /* Number of subqueries */
u8 bSelectDepthFirst; /* Do subqueries first */
union { /* Extra data for callback */ union { /* Extra data for callback */
NameContext *pNC; /* Naming context */ NameContext *pNC; /* Naming context */
int i; /* Integer value */ int i; /* Integer value */
@@ -3354,9 +3355,9 @@ const char *sqlite3JournalModename(int);
#ifndef SQLITE_OMIT_CTE #ifndef SQLITE_OMIT_CTE
With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
void sqlite3WithDelete(sqlite3*,With*); void sqlite3WithDelete(sqlite3*,With*);
void sqlite3WithPush(Parse*, With*); void sqlite3WithPush(Parse*, With*, u8);
#else #else
#define sqlite3WithPush(x,y) #define sqlite3WithPush(x,y,z)
#define sqlite3WithDelete(x,y) #define sqlite3WithDelete(x,y)
#endif #endif

View File

@@ -494,8 +494,7 @@ abort_parse:
sqlite3DeleteTable(db, pParse->pNewTable); sqlite3DeleteTable(db, pParse->pNewTable);
} }
assert( pParse->pWith==0 || pParse->pWith->pOuter==0 ); if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith);
sqlite3WithDelete(db, pParse->pWith);
sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DeleteTrigger(db, pParse->pNewTrigger);
for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]); for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
sqlite3DbFree(db, pParse->azVar); sqlite3DbFree(db, pParse->azVar);

View File

@@ -113,9 +113,12 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
/* /*
** Call sqlite3WalkExpr() for every expression in Select statement p. ** Call sqlite3WalkExpr() for every expression in Select statement p.
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
** on the compound select chain, p->pPrior. Invoke the xSelectCallback() ** on the compound select chain, p->pPrior.
** either before or after the walk of expressions and FROM clause, depending **
** on whether pWalker->bSelectDepthFirst is false or true, respectively. ** If it is not NULL, the xSelectCallback() callback is invoked before
** the walk of the expressions and FROM clause. The xSelectCallback2()
** method, if it is not NULL, is invoked following the walk of the
** expressions and FROM clause.
** **
** Return WRC_Continue under normal conditions. Return WRC_Abort if ** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request. ** there is an abort request.
@@ -125,11 +128,13 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
*/ */
int sqlite3WalkSelect(Walker *pWalker, Select *p){ int sqlite3WalkSelect(Walker *pWalker, Select *p){
int rc; int rc;
if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue; if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
return WRC_Continue;
}
rc = WRC_Continue; rc = WRC_Continue;
pWalker->walkerDepth++; pWalker->walkerDepth++;
while( p ){ while( p ){
if( !pWalker->bSelectDepthFirst ){ if( pWalker->xSelectCallback ){
rc = pWalker->xSelectCallback(pWalker, p); rc = pWalker->xSelectCallback(pWalker, p);
if( rc ) break; if( rc ) break;
} }
@@ -139,12 +144,8 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){
pWalker->walkerDepth--; pWalker->walkerDepth--;
return WRC_Abort; return WRC_Abort;
} }
if( pWalker->bSelectDepthFirst ){ if( pWalker->xSelectCallback2 ){
rc = pWalker->xSelectCallback(pWalker, p); pWalker->xSelectCallback2(pWalker, p);
/* Depth-first search is currently only used for
** selectAddSubqueryTypeInfo() and that routine always returns
** WRC_Continue (0). So the following branch is never taken. */
if( NEVER(rc) ) break;
} }
p = p->pPrior; p = p->pPrior;
} }

56
test/with2.test Normal file
View File

@@ -0,0 +1,56 @@
# 2014 January 11
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the WITH clause.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix with2
do_execsql_test 1.0 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
}
do_execsql_test 1.1 {
WITH x1 AS (SELECT * FROM t1)
SELECT sum(a) FROM x1;
} {3}
do_execsql_test 1.2 {
WITH x1 AS (SELECT * FROM t1)
SELECT (SELECT sum(a) FROM x1);
} {3}
do_execsql_test 1.3 {
WITH x1 AS (SELECT * FROM t1)
SELECT (SELECT sum(a) FROM x1);
} {3}
do_execsql_test 1.4 {
CREATE TABLE t2(i);
INSERT INTO t2 VALUES(2);
INSERT INTO t2 VALUES(3);
INSERT INTO t2 VALUES(5);
WITH x1 AS (SELECT i FROM t2),
i(a) AS (
SELECT min(i)-1 FROM x1 UNION SELECT a+1 FROM i WHERE a<10
)
SELECT a FROM i WHERE a NOT IN x1
} {1 4 6 7 8 9 10}
finish_test