mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-14 00:22:38 +03:00
Resolve table names within CTEs in the context in which the CTE is declared, not the context in which it is used.
FossilOrigin-Name: a7323838bbd354a1c2f339e5e0f164f0eada47b3
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
||||
C Add\stests\sthat\sverify\sthat\skeywords\sWITH,\sWITHOUT,\sand\sRECURSIVE\scan\sstill\nbe\sused\sas\stable\sand\scolumn\snames.
|
||||
D 2014-01-17T16:19:01.842
|
||||
C Resolve\stable\snames\swithin\sCTEs\sin\sthe\scontext\sin\swhich\sthe\sCTE\sis\sdeclared,\snot\sthe\scontext\sin\swhich\sit\sis\sused.
|
||||
D 2014-01-17T17:40:46.168
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -219,7 +219,7 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c b17dd5c3ef4647190bd80f51b56e366c7b12f6e5
|
||||
F src/select.c a13cf4a450534bcbdf1cc840d695e259cd4a1409
|
||||
F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
@@ -1092,7 +1092,7 @@ F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test 90490c75e98e1914d84b7cef9e636b48917a020f
|
||||
F test/with2.test 790c4b7ab3f4eb6984a3bbdae8d4ab429ebe9259
|
||||
F test/with2.test 21057990b59eb652a0a30c6a421fac9daad4412d
|
||||
F test/withM.test 52448ce23e1c2ecba79d10e130ee49ce9f9a2a7a
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
@@ -1151,7 +1151,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P c8eb11635a356182611ce2ccb8f358b6c453486e
|
||||
R c791b577950f1652718e7fda0d0264df
|
||||
U drh
|
||||
Z 3da1c453f8a3e6f09e0b3d8bdad77daa
|
||||
P 9ca18a0191db6a9b0763e2f0b3b35d23099fb71b
|
||||
R b5a3302763f84d4efb48b14faba25e2d
|
||||
U dan
|
||||
Z c42b677f74f4986c260cd54897199c85
|
||||
|
||||
@@ -1 +1 @@
|
||||
9ca18a0191db6a9b0763e2f0b3b35d23099fb71b
|
||||
a7323838bbd354a1c2f339e5e0f164f0eada47b3
|
||||
30
src/select.c
30
src/select.c
@@ -3507,8 +3507,15 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
** FROM clause element pItem is really a common-table-expression (CTE)
|
||||
** then return a pointer to the CTE definition for that table. Otherwise
|
||||
** return NULL.
|
||||
**
|
||||
** If a non-NULL value is returned, set *ppContext to point to the With
|
||||
** object that the returned CTE belongs to.
|
||||
*/
|
||||
static struct Cte *searchWith(With *pWith, struct SrcList_item *pItem){
|
||||
static struct Cte *searchWith(
|
||||
With *pWith, /* Current outermost WITH clause */
|
||||
struct SrcList_item *pItem, /* FROM clause element to resolve */
|
||||
With **ppContext /* OUT: WITH clause return value belongs to */
|
||||
){
|
||||
const char *zName;
|
||||
if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
|
||||
With *p;
|
||||
@@ -3516,6 +3523,7 @@ static struct Cte *searchWith(With *pWith, struct SrcList_item *pItem){
|
||||
int i;
|
||||
for(i=0; i<p->nCte; i++){
|
||||
if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
||||
*ppContext = p;
|
||||
return &p->a[i];
|
||||
}
|
||||
}
|
||||
@@ -3562,19 +3570,21 @@ static int withExpand(
|
||||
Walker *pWalker,
|
||||
struct SrcList_item *pFrom
|
||||
){
|
||||
Table *pTab;
|
||||
Parse *pParse = pWalker->pParse;
|
||||
sqlite3 *db = pParse->db;
|
||||
struct Cte *pCte;
|
||||
struct Cte *pCte; /* Matched CTE (or NULL if no match) */
|
||||
With *pWith; /* WITH clause that pCte belongs to */
|
||||
|
||||
assert( pFrom->pTab==0 );
|
||||
|
||||
pCte = searchWith(pParse->pWith, pFrom);
|
||||
pCte = searchWith(pParse->pWith, pFrom, &pWith);
|
||||
if( pCte ){
|
||||
Table *pTab;
|
||||
ExprList *pEList;
|
||||
Select *pSel;
|
||||
Select *pLeft; /* Left-most SELECT statement */
|
||||
int bMayRecursive; /* True if compound joined by UNION [ALL] */
|
||||
With *pSavedWith; /* Initial value of pParse->pWith */
|
||||
|
||||
/* If pCte->zErr is non-NULL at this point, then this is an illegal
|
||||
** recursive reference to CTE pCte. Leave an error in pParse and return
|
||||
@@ -3582,7 +3592,7 @@ static int withExpand(
|
||||
** In this case, proceed. */
|
||||
if( pCte->zErr ){
|
||||
sqlite3ErrorMsg(pParse, pCte->zErr, pCte->zName);
|
||||
return WRC_Abort;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
@@ -3621,11 +3631,13 @@ static int withExpand(
|
||||
sqlite3ErrorMsg(
|
||||
pParse, "multiple references to recursive table: %s", pCte->zName
|
||||
);
|
||||
return WRC_Abort;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
|
||||
|
||||
pCte->zErr = "circular reference: %s";
|
||||
pSavedWith = pParse->pWith;
|
||||
pParse->pWith = pWith;
|
||||
sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
|
||||
|
||||
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
||||
@@ -3635,12 +3647,13 @@ static int withExpand(
|
||||
sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
|
||||
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
|
||||
);
|
||||
return WRC_Abort;
|
||||
pParse->pWith = pSavedWith;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pEList = pCte->pCols;
|
||||
}
|
||||
selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
|
||||
|
||||
selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
|
||||
if( bMayRecursive ){
|
||||
if( pSel->selFlags & SF_Recursive ){
|
||||
pCte->zErr = "multiple recursive references: %s";
|
||||
@@ -3650,6 +3663,7 @@ static int withExpand(
|
||||
sqlite3WalkSelect(pWalker, pSel);
|
||||
}
|
||||
pCte->zErr = 0;
|
||||
pParse->pWith = pSavedWith;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -50,7 +50,24 @@ do_execsql_test 1.4 {
|
||||
SELECT a FROM i WHERE a NOT IN x1
|
||||
} {1 4 6 7 8 9 10}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
WITH x1 AS (SELECT a FROM t1),
|
||||
x2 AS (SELECT i FROM t2),
|
||||
x3 AS (SELECT * FROM x1, x2 WHERE x1.a IN x2 AND x2.i IN x1)
|
||||
SELECT * FROM x3
|
||||
} {2 2}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
CREATE TABLE t3 AS SELECT 3 AS x;
|
||||
CREATE TABLE t4 AS SELECT 4 AS x;
|
||||
|
||||
WITH x1 AS (SELECT * FROM t3),
|
||||
x2 AS (
|
||||
WITH t3 AS (SELECT * FROM t4)
|
||||
SELECT * FROM x1
|
||||
)
|
||||
SELECT * FROM x2;
|
||||
} {3}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user