diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 1 | ||||
-rw-r--r-- | src/select.c | 66 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 |
3 files changed, 25 insertions, 45 deletions
diff --git a/src/build.c b/src/build.c index c7d956a9b..353c93807 100644 --- a/src/build.c +++ b/src/build.c @@ -4245,6 +4245,7 @@ With *sqlite3WithAdd( pNew->a[pNew->nCte].pSelect = pQuery; pNew->a[pNew->nCte].pCols = pArglist; pNew->a[pNew->nCte].zName = zName; + pNew->a[pNew->nCte].zErr = 0; pNew->nCte++; } diff --git a/src/select.c b/src/select.c index d70d815a2..7b6c5e9c2 100644 --- a/src/select.c +++ b/src/select.c @@ -3534,44 +3534,6 @@ void sqlite3WithPush(Parse *pParse, With *pWith){ } /* -** If argument pCte is not NULL, check if it is already a part of the -** stack of CTEs stored by the parser. If so, this indicates an illegal -** recursive reference in a CTE, set of mutually recursive CTEs. Store -** an error in the parser and return SQLITE_ERROR if this is the case. -** -** Otherwise, if pCte is not already part of the stack of CTEs stored -** in the parser, push it onto the stop of that stack. -*/ -static int ctePush(Parse *pParse, struct Cte *pCte){ - if( pCte ){ - struct Cte *p; - for(p=pParse->pCte; p; p=p->pOuterCte){ - if( p==pCte ){ - sqlite3ErrorMsg( - pParse, "illegal recursive defininition in cte: %s", pCte->zName - ); - return SQLITE_ERROR; - } - } - - pCte->pOuterCte = pParse->pCte; - pParse->pCte = pCte; - } - return SQLITE_OK; -} -/* -** If argument pCte is not NULL, it must be a pointer to the CTE currently -** on top of the stack of CTEs stored in the parser. Remove it from that -** stack. -*/ -static void ctePop(Parse *pParse, struct Cte *pCte){ - if( pCte ){ - assert( pParse->pCte==pCte ); - pParse->pCte = pCte->pOuterCte; - } -} - -/* ** This function checks if argument pFrom refers to a CTE declared by ** a WITH clause on the stack currently maintained by the parser. And, ** if currently processing a CTE expression, if it is a recursive @@ -3602,6 +3564,16 @@ static int withExpand( ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ + int bMayRecursive; /* True if compound joined by UNION [ALL] */ + + /* 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 + ** early. If pCte->zErr is NULL, then this is not a recursive reference. + ** In this case, proceed. */ + if( pCte->zErr ){ + sqlite3ErrorMsg(pParse, pCte->zErr, pCte->zName); + return WRC_Abort; + } pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; @@ -3616,7 +3588,8 @@ static int withExpand( /* Check if this is a recursive CTE. */ pSel = pFrom->pSelect; - if( pSel->op==TK_ALL || pSel->op==TK_UNION ){ + bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); + if( bMayRecursive ){ int i; SrcList *pSrc = pFrom->pSelect->pSrc; for(i=0; i<pSrc->nSrc; i++){ @@ -3642,8 +3615,8 @@ static int withExpand( } 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); + pCte->zErr = "circular reference to cte: %s"; + sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel); for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; @@ -3658,8 +3631,15 @@ static int withExpand( } selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol); - if( pSel->selFlags & SF_Recursive ) sqlite3WalkSelect(pWalker, pSel); - ctePop(pParse, pCte); + if( bMayRecursive ){ + if( pSel->selFlags & SF_Recursive ){ + pCte->zErr = "multiple recursive references in cte: %s"; + }else{ + pCte->zErr = "recursive reference may not appear in sub-query: %s"; + } + sqlite3WalkSelect(pWalker, pSel); + } + pCte->zErr = 0; } return SQLITE_OK; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 43a1a57b0..3f29f58d4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2371,7 +2371,6 @@ struct Parse { Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ - struct Cte *pCte; /* Current CTE, or NULL */ }; /* @@ -2650,7 +2649,7 @@ struct With { char *zName; /* Name of this CTE */ ExprList *pCols; /* List of explicit column names, or NULL */ Select *pSelect; /* The definition of this CTE */ - struct Cte *pOuterCte; /* Next WITH clause in outer context */ + const char *zErr; /* Error message for circular references */ } a[1]; }; |