mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Allow only a single recursive reference in a recursive CTE. Also require that this reference is not part of a sub-query.
FossilOrigin-Name: a296b73360d34c9364eceb2cc09a9a92adc4abb8
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Disable\sthe\sflattening\soptimization\sif\sthe\sparent\squery\sis\sthe\srecursive\spart\sof\sa\srecursive\sCTE\sand\sthe\ssub-query\sis\sa\scompound\squery.
|
C Allow\sonly\sa\ssingle\srecursive\sreference\sin\sa\srecursive\sCTE.\sAlso\srequire\sthat\sthis\sreference\sis\snot\spart\sof\sa\ssub-query.
|
||||||
D 2014-01-16T10:58:39.954
|
D 2014-01-16T18:34:33.041
|
||||||
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
|
||||||
@@ -175,7 +175,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
|||||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||||
F src/delete.c 91e1321021db5dc266360531b8b6550009d771ff
|
F src/delete.c 91e1321021db5dc266360531b8b6550009d771ff
|
||||||
F src/expr.c c09e34fa7c58995009135b81f83cb62a676ad181
|
F src/expr.c e239763d8b43356fa1f46f1cf41d62a076f7f72e
|
||||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||||
F src/func.c 6325ac2ec10833ccf4d5c36d323709221d37ea19
|
F src/func.c 6325ac2ec10833ccf4d5c36d323709221d37ea19
|
||||||
@@ -219,12 +219,12 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
|||||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||||
F src/resolve.c ae278d8ce037883323f677e78c241f64289f12ec
|
F src/resolve.c ae278d8ce037883323f677e78c241f64289f12ec
|
||||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||||
F src/select.c 29976d169853492a20d3201e8a83eeefa39a868f
|
F src/select.c 2d2da29fd4c877646109f7d2fba26b5cc454cd37
|
||||||
F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
|
F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
|
||||||
F src/sqlite.h.in d94a8b89522f526ba711182ee161e06f8669bcc9
|
F src/sqlite.h.in d94a8b89522f526ba711182ee161e06f8669bcc9
|
||||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||||
F src/sqliteInt.h 6db445ce172c249c29d8f532af64fd7051fe05dd
|
F src/sqliteInt.h b30bd95081be525b32551f180cf43ccfaff9f5bc
|
||||||
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
|
||||||
@@ -280,7 +280,7 @@ F src/update.c c2706a6eb232a96345c35b7e1e75a188e26812bb
|
|||||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||||
F src/util.c e71f19b272f05c8695cf747b4bac1732685f9e5c
|
F src/util.c e71f19b272f05c8695cf747b4bac1732685f9e5c
|
||||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||||
F src/vdbe.c b06d79951a3f0da9cb41cb0aae5fdf5612f718a9
|
F src/vdbe.c ccc8594e89751966022642464ec2b5c5fa7840a2
|
||||||
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
||||||
F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56
|
F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56
|
||||||
F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad
|
F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad
|
||||||
@@ -293,7 +293,7 @@ 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 e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||||
F src/where.c 27eb508c4184599a826e2ef3b4319cd28ba2c7af
|
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
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
@@ -1150,7 +1150,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 7f953b568baa3eede0b9c144be0b9bc86496341a
|
P 6bfa387e82de47ca1f40225fe28d873e29d6f481
|
||||||
R 1f82ce2970e79b42a60992cde0f0f626
|
R d0f7d170eccd6b8c29b55960683e8b9a
|
||||||
U dan
|
U dan
|
||||||
Z da04231961fbad92750efdf2d0f0da36
|
Z 617b83d8e92edcc7afd63e19b605afe5
|
||||||
|
@@ -1 +1 @@
|
|||||||
6bfa387e82de47ca1f40225fe28d873e29d6f481
|
a296b73360d34c9364eceb2cc09a9a92adc4abb8
|
@@ -1065,7 +1065,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
|||||||
pNew->addrOpenEphm[1] = -1;
|
pNew->addrOpenEphm[1] = -1;
|
||||||
pNew->addrOpenEphm[2] = -1;
|
pNew->addrOpenEphm[2] = -1;
|
||||||
pNew->pWith = withDup(db, p->pWith);
|
pNew->pWith = withDup(db, p->pWith);
|
||||||
pNew->pRecurse = p->pRecurse;
|
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
88
src/select.c
88
src/select.c
@@ -1744,7 +1744,7 @@ static int multiSelect(
|
|||||||
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
|
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
|
||||||
*/
|
*/
|
||||||
assert( p && p->pPrior ); /* Calling function guarantees this much */
|
assert( p && p->pPrior ); /* Calling function guarantees this much */
|
||||||
assert( p->pRecurse==0 || p->op==TK_ALL || p->op==TK_UNION );
|
assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION );
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
pPrior = p->pPrior;
|
pPrior = p->pPrior;
|
||||||
assert( pPrior->pRightmost!=pPrior );
|
assert( pPrior->pRightmost!=pPrior );
|
||||||
@@ -1794,27 +1794,36 @@ static int multiSelect(
|
|||||||
/* If this is a recursive query, check that there is no ORDER BY or
|
/* If this is a recursive query, check that there is no ORDER BY or
|
||||||
** LIMIT clause. Neither of these are supported. */
|
** LIMIT clause. Neither of these are supported. */
|
||||||
assert( p->pOffset==0 || p->pLimit );
|
assert( p->pOffset==0 || p->pLimit );
|
||||||
if( p->pRecurse && (p->pOrderBy || p->pLimit) ){
|
if( (p->selFlags & SF_Recursive) && (p->pOrderBy || p->pLimit) ){
|
||||||
sqlite3ErrorMsg(pParse, "%s in a recursive query is not allowed",
|
sqlite3ErrorMsg(pParse, "%s in a recursive query is not allowed",
|
||||||
p->pOrderBy ? "ORDER BY" : "LIMIT"
|
p->pOrderBy ? "ORDER BY" : "LIMIT"
|
||||||
);
|
);
|
||||||
goto multi_select_end;
|
goto multi_select_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p->pRecurse ){
|
if( p->selFlags & SF_Recursive ){
|
||||||
|
SrcList *pSrc = p->pSrc;
|
||||||
int nCol = p->pEList->nExpr;
|
int nCol = p->pEList->nExpr;
|
||||||
int addrNext;
|
int addrNext;
|
||||||
int addrSwap;
|
int addrSwap;
|
||||||
int iCont, iBreak;
|
int iCont, iBreak;
|
||||||
int tmp1, tmp2; /* Cursors used to access temporary tables */
|
int tmp1; /* Intermediate table */
|
||||||
|
int tmp2; /* Next intermediate table */
|
||||||
int tmp3 = 0; /* To ensure unique results if UNION */
|
int tmp3 = 0; /* To ensure unique results if UNION */
|
||||||
int eDest = SRT_Table;
|
int eDest = SRT_Table;
|
||||||
SelectDest tmp2dest;
|
SelectDest tmp2dest;
|
||||||
|
int i;
|
||||||
|
|
||||||
iBreak = sqlite3VdbeMakeLabel(v);
|
iBreak = sqlite3VdbeMakeLabel(v);
|
||||||
iCont = sqlite3VdbeMakeLabel(v);
|
iCont = sqlite3VdbeMakeLabel(v);
|
||||||
|
|
||||||
tmp1 = pParse->nTab++;
|
for(i=0; ALWAYS(i<pSrc->nSrc); i++){
|
||||||
|
if( pSrc->a[i].isRecursive ){
|
||||||
|
tmp1 = pSrc->a[i].iCursor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tmp2 = pParse->nTab++;
|
tmp2 = pParse->nTab++;
|
||||||
if( p->op==TK_UNION ){
|
if( p->op==TK_UNION ){
|
||||||
eDest = SRT_DistTable;
|
eDest = SRT_DistTable;
|
||||||
@@ -1848,11 +1857,7 @@ static int multiSelect(
|
|||||||
** SELECT is running, the contents of tmp1 are read by recursive
|
** SELECT is running, the contents of tmp1 are read by recursive
|
||||||
** references to the current CTE. */
|
** references to the current CTE. */
|
||||||
p->pPrior = 0;
|
p->pPrior = 0;
|
||||||
p->pRecurse->tnum = tmp1;
|
|
||||||
assert( (p->pRecurse->tabFlags & TF_Recursive)==0 );
|
|
||||||
p->pRecurse->tabFlags |= TF_Recursive;
|
|
||||||
rc = sqlite3Select(pParse, p, &tmp2dest);
|
rc = sqlite3Select(pParse, p, &tmp2dest);
|
||||||
p->pRecurse->tabFlags &= ~TF_Recursive;
|
|
||||||
assert( p->pPrior==0 );
|
assert( p->pPrior==0 );
|
||||||
p->pPrior = pPrior;
|
p->pPrior = pPrior;
|
||||||
if( rc ) goto multi_select_end;
|
if( rc ) goto multi_select_end;
|
||||||
@@ -3009,8 +3014,8 @@ static int flattenSubquery(
|
|||||||
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
|
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
|
||||||
return 0; /* Restriction (21) */
|
return 0; /* Restriction (21) */
|
||||||
}
|
}
|
||||||
if( pSub->pRecurse ) return 0; /* Restriction (22) */
|
if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */
|
||||||
if( p->pRecurse && pSub->pPrior ) return 0; /* Restriction (23) */
|
if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */
|
||||||
|
|
||||||
/* OBSOLETE COMMENT 1:
|
/* OBSOLETE COMMENT 1:
|
||||||
** Restriction 3: If the subquery is a join, make sure the subquery is
|
** Restriction 3: If the subquery is a join, make sure the subquery is
|
||||||
@@ -3593,19 +3598,10 @@ static int withExpand(
|
|||||||
assert( pFrom->pTab==0 );
|
assert( pFrom->pTab==0 );
|
||||||
|
|
||||||
pCte = searchWith(pParse->pWith, pFrom);
|
pCte = searchWith(pParse->pWith, pFrom);
|
||||||
if( pCte==0 ){
|
if( pCte ){
|
||||||
/* no-op */
|
|
||||||
}else if( pCte==pParse->pCte && (pTab = pCte->pTab) ){
|
|
||||||
/* This is the recursive part of a recursive CTE */
|
|
||||||
assert( pFrom->pTab==0 && pFrom->isRecursive==0 && pFrom->pSelect==0 );
|
|
||||||
pFrom->pTab = pTab;
|
|
||||||
pFrom->isRecursive = 1;
|
|
||||||
pTab->nRef++;
|
|
||||||
}else{
|
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
Select *pSel;
|
Select *pSel;
|
||||||
Select *pLeft; /* Left-most SELECT statement */
|
Select *pLeft; /* Left-most SELECT statement */
|
||||||
int bRecursive;
|
|
||||||
|
|
||||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||||
if( pTab==0 ) return WRC_Abort;
|
if( pTab==0 ) return WRC_Abort;
|
||||||
@@ -3618,16 +3614,37 @@ static int withExpand(
|
|||||||
if( db->mallocFailed ) return SQLITE_NOMEM;
|
if( db->mallocFailed ) return SQLITE_NOMEM;
|
||||||
assert( pFrom->pSelect );
|
assert( pFrom->pSelect );
|
||||||
|
|
||||||
if( ctePush(pParse, pCte) ) return WRC_Abort;
|
/* Check if this is a recursive CTE. */
|
||||||
pSel = pFrom->pSelect;
|
pSel = pFrom->pSelect;
|
||||||
bRecursive = (pSel->op==TK_ALL || pSel->op==TK_UNION);
|
if( pSel->op==TK_ALL || pSel->op==TK_UNION ){
|
||||||
if( bRecursive ){
|
int i;
|
||||||
assert( pSel->pPrior );
|
SrcList *pSrc = pFrom->pSelect->pSrc;
|
||||||
sqlite3WalkSelect(pWalker, pSel->pPrior);
|
for(i=0; i<pSrc->nSrc; i++){
|
||||||
}else{
|
struct SrcList_item *pItem = &pSrc->a[i];
|
||||||
sqlite3WalkSelect(pWalker, pSel);
|
if( pItem->zDatabase==0
|
||||||
|
&& pItem->zName!=0
|
||||||
|
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
|
||||||
|
){
|
||||||
|
pItem->pTab = pTab;
|
||||||
|
pItem->isRecursive = 1;
|
||||||
|
pTab->nRef++;
|
||||||
|
pSel->selFlags |= SF_Recursive;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only one recursive reference is permitted. */
|
||||||
|
if( pTab->nRef>2 ){
|
||||||
|
sqlite3ErrorMsg(
|
||||||
|
pParse, "multiple recursive references in cte: %s", pCte->zName
|
||||||
|
);
|
||||||
|
return WRC_Abort;
|
||||||
|
}
|
||||||
|
assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
|
||||||
|
|
||||||
|
if( ctePush(pParse, pCte) ) return WRC_Abort;
|
||||||
|
sqlite3WalkSelect(pWalker, pTab->nRef==2 ? pSel->pPrior : pSel);
|
||||||
|
|
||||||
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
||||||
pEList = pLeft->pEList;
|
pEList = pLeft->pEList;
|
||||||
if( pCte->pCols ){
|
if( pCte->pCols ){
|
||||||
@@ -3639,20 +3656,9 @@ static int withExpand(
|
|||||||
}
|
}
|
||||||
pEList = pCte->pCols;
|
pEList = pCte->pCols;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
|
selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
|
||||||
|
|
||||||
if( bRecursive ){
|
if( pSel->selFlags & SF_Recursive ) sqlite3WalkSelect(pWalker, pSel);
|
||||||
int nRef = pTab->nRef;
|
|
||||||
pCte->pTab = pTab;
|
|
||||||
sqlite3WalkSelect(pWalker, pSel);
|
|
||||||
pCte->pTab = 0;
|
|
||||||
if( pTab->nRef > nRef){
|
|
||||||
pSel->pRecurse = pTab;
|
|
||||||
assert( pTab->tnum==0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctePop(pParse, pCte);
|
ctePop(pParse, pCte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3715,6 +3721,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|||||||
*/
|
*/
|
||||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
|
assert( pFrom->isRecursive==0 || pFrom->pTab );
|
||||||
|
if( pFrom->isRecursive ) continue;
|
||||||
if( pFrom->pTab!=0 ){
|
if( pFrom->pTab!=0 ){
|
||||||
/* 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. */
|
||||||
|
@@ -2131,7 +2131,6 @@ struct NameContext {
|
|||||||
*/
|
*/
|
||||||
struct Select {
|
struct Select {
|
||||||
ExprList *pEList; /* The fields of the result */
|
ExprList *pEList; /* The fields of the result */
|
||||||
Table *pRecurse; /* Non-NULL for the recursive part of recursive CTE */
|
|
||||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||||
u16 selFlags; /* Various SF_* values */
|
u16 selFlags; /* Various SF_* values */
|
||||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||||
@@ -2165,6 +2164,7 @@ struct Select {
|
|||||||
#define SF_Materialize 0x0100 /* Force materialization of views */
|
#define SF_Materialize 0x0100 /* Force materialization of views */
|
||||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||||
|
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2640,7 +2640,7 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
|
|||||||
#define WRC_Abort 2 /* Abandon the tree walk */
|
#define WRC_Abort 2 /* Abandon the tree walk */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of this structure represents a set of on or more CTEs
|
** An instance of this structure represents a set of one or more CTEs
|
||||||
** (common table expressions) created by a single WITH clause.
|
** (common table expressions) created by a single WITH clause.
|
||||||
*/
|
*/
|
||||||
struct With {
|
struct With {
|
||||||
@@ -2651,7 +2651,6 @@ struct With {
|
|||||||
ExprList *pCols; /* List of explicit column names, or NULL */
|
ExprList *pCols; /* List of explicit column names, or NULL */
|
||||||
Select *pSelect; /* The definition of this CTE */
|
Select *pSelect; /* The definition of this CTE */
|
||||||
struct Cte *pOuterCte; /* Next WITH clause in outer context */
|
struct Cte *pOuterCte; /* Next WITH clause in outer context */
|
||||||
Table *pTab; /* Table object for this CTE */
|
|
||||||
} a[1];
|
} a[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
23
src/vdbe.c
23
src/vdbe.c
@@ -3370,29 +3370,6 @@ case OP_OpenEphemeral: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_CTE
|
#ifndef SQLITE_OMIT_CTE
|
||||||
/* Opcode: OpenEphreader P1 P2 * * *
|
|
||||||
**
|
|
||||||
** P2 is a cursor opened by the OpenEphemeral opcode. This opcode opens
|
|
||||||
** a new read-only cursor named P1 that accesses the same epheremal table
|
|
||||||
** as P2.
|
|
||||||
*/
|
|
||||||
case OP_OpenEphreader: {
|
|
||||||
VdbeCursor *pEph;
|
|
||||||
VdbeCursor *pCx;
|
|
||||||
Pgno pgno;
|
|
||||||
|
|
||||||
pEph = p->apCsr[pOp->p2];
|
|
||||||
pCx = allocateCursor(p, pOp->p1, pEph->nField, -1, 1);
|
|
||||||
if( pCx==0 ) goto no_mem;
|
|
||||||
pCx->nullRow = 1;
|
|
||||||
pCx->pKeyInfo = pEph->pKeyInfo;
|
|
||||||
pCx->isTable = pEph->isTable;
|
|
||||||
pCx->isOrdered = pEph->isOrdered;
|
|
||||||
pgno = MASTER_ROOT + !pCx->isTable;
|
|
||||||
rc = sqlite3BtreeCursor(pEph->pBt, pgno, 0, pCx->pKeyInfo, pCx->pCursor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: SwapCursors P1 P2 * * *
|
/* Opcode: SwapCursors P1 P2 * * *
|
||||||
**
|
**
|
||||||
** Parameters P1 and P2 are both cursors opened by the OpenEphemeral
|
** Parameters P1 and P2 are both cursors opened by the OpenEphemeral
|
||||||
|
@@ -5654,13 +5654,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||||
pLoop = pLevel->pWLoop;
|
pLoop = pLevel->pWLoop;
|
||||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
|
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
|
||||||
#ifndef SQLITE_OMIT_CTE
|
/* Do nothing */
|
||||||
if( pTab->tabFlags & TF_Recursive ){
|
|
||||||
int iCur = pTabItem->iCursor;
|
|
||||||
sqlite3VdbeAddOp2(v, OP_OpenEphreader, iCur, pTab->tnum);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Otherwise do nothing */
|
|
||||||
}else
|
}else
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
||||||
|
Reference in New Issue
Block a user