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:
21
manifest
21
manifest
@@ -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
|
||||||
|
@@ -1 +1 @@
|
|||||||
f68c6c4d36481526a9348244adc571ea282dc9eb
|
6a549187ed8b5ed50daefa676ff666ae2ed43346
|
12
src/parse.y
12
src/parse.y
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
61
src/select.c
61
src/select.c
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
23
src/walker.c
23
src/walker.c
@@ -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
56
test/with2.test
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user