aboutsummaryrefslogtreecommitdiff
path: root/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/select.c')
-rw-r--r--src/select.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/src/select.c b/src/select.c
index 3da69943f..a13abe375 100644
--- a/src/select.c
+++ b/src/select.c
@@ -4540,6 +4540,10 @@ static int propagateConstants(
** changes to the WHERE clause of the inner query could change the
** window over which window functions are calculated).
**
+** (7) The inner query is a Common Table Expression (CTE) that should
+** be materialized. (This restriction is implemented in the calling
+** routine.)
+**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
@@ -4923,6 +4927,7 @@ static int resolveFromTermToCte(
int bMayRecursive; /* True if compound joined by UNION [ALL] */
With *pSavedWith; /* Initial value of pParse->pWith */
int iRecTab = -1; /* Cursor for recursive table */
+ CteUse *pCteUse;
/* If pCte->zCteErr is non-NULL at this point, then this is an illegal
** recursive reference to CTE pCte. Leave an error in pParse and return
@@ -4937,14 +4942,16 @@ static int resolveFromTermToCte(
assert( pFrom->pTab==0 );
pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return 2;
- if( pCte->pUse==0 ){
- pCte->pUse = sqlite3DbMallocZero(db, sizeof(pCte->pUse[0]));
- if( pCte->pUse==0
- || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCte->pUse)==0
+ pCteUse = pCte->pUse;
+ if( pCteUse==0 ){
+ pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
+ if( pCteUse==0
+ || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0
){
sqlite3DbFree(db, pTab);
return 2;
}
+ pCteUse->eM10d = pCte->eM10d;
}
pFrom->pTab = pTab;
pTab->nTabRef = 1;
@@ -4956,8 +4963,11 @@ static int resolveFromTermToCte(
if( db->mallocFailed ) return 2;
assert( pFrom->pSelect );
pFrom->fg.isCte = 1;
- pFrom->u2.pCteUse = pCte->pUse;
- pCte->pUse->nUse++;
+ pFrom->u2.pCteUse = pCteUse;
+ pCteUse->nUse++;
+ if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
+ pCteUse->eM10d = M10d_Yes;
+ }
/* Check if this is a recursive CTE. */
pRecTerm = pSel = pFrom->pSelect;
@@ -6226,7 +6236,7 @@ int sqlite3Select(
** inside the subquery. This can help the subquery to run more efficiently.
*/
if( OptimizationEnabled(db, SQLITE_PushDown)
- && (pItem->fg.isCte==0 || pItem->u2.pCteUse->nUse<=1)
+ && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d==M10d_Yes)
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
(pItem->fg.jointype & JT_OUTER)!=0)
){
@@ -6250,7 +6260,7 @@ int sqlite3Select(
** The subquery is implemented as a co-routine if:
** (1) the subquery is guaranteed to be the outer loop (so that
** it does not need to be computed more than once), and
- ** (2) the subquery is not a CTE that is used more then once.
+ ** (2) the subquery is not a CTE that should be materialized
**
** TODO: Are there other reasons beside (1) and (2) to use a co-routine
** implementation?
@@ -6258,7 +6268,7 @@ int sqlite3Select(
if( i==0
&& (pTabList->nSrc==1
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
- && (pItem->fg.isCte==0 || pItem->u2.pCteUse->nUse<2) /* (2) */
+ && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.