Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | When resolving names, consider a reference to a recursive CTE column as equivalent to a reference to the outermost name-context. This ensures that correlated sub-queries are correctly identified as such. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | common-table-expr |
Files: | files | file ages | folders |
SHA1: |
61be2da0ae623c1572819481508b044e |
User & Date: | dan 2014-01-15 18:12:00.359 |
Context
2014-01-15
| ||
18:21 | Disable automatic indices on recursive CTE references. (check-in: 28aa6db8c8 user: dan tags: common-table-expr) | |
18:12 | When resolving names, consider a reference to a recursive CTE column as equivalent to a reference to the outermost name-context. This ensures that correlated sub-queries are correctly identified as such. (check-in: 61be2da0ae user: dan tags: common-table-expr) | |
15:27 | Return an error if a CTE specifies a different number of columns than its SELECT statement returns. (check-in: 9a514b50e4 user: dan tags: common-table-expr) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->viaCoroutine = pOldItem->viaCoroutine; pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->pIndex = pOldItem->pIndex; pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nRef++; } | > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->viaCoroutine = pOldItem->viaCoroutine; pNewItem->isRecursive = pOldItem->isRecursive; pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->pIndex = pOldItem->pIndex; pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nRef++; } |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 505 506 507 508 509 510 511 | pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); if( pExpr->op!=TK_AS ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; | > > > > > > > > | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); if( pExpr->op!=TK_AS ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } /* If this expression reads a column value from a recursive CTE ** reference, then this is equivalent to reading from the outermost ** available name-context. */ if( pMatch && pMatch->isRecursive ){ while( pNC->pNext ) pNC = pNC->pNext; } /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 | sqlite3 *db = pParse->db; assert( pFrom->pSelect==0 ); assert( pFrom->pTab==0 ); if( pCte==pParse->pCte && (pTab = pCte->pTab) ){ /* This is the recursive part of a recursive CTE */ pFrom->pTab = pTab; pTab->nRef++; }else{ ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ int bRecursive; | > > | 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 | sqlite3 *db = pParse->db; assert( pFrom->pSelect==0 ); assert( pFrom->pTab==0 ); if( pCte==pParse->pCte && (pTab = pCte->pTab) ){ /* This is the recursive part of a recursive CTE */ assert( pFrom->pTab==0 && pFrom->isRecursive==0 ); pFrom->pTab = pTab; pFrom->isRecursive = 1; pTab->nRef++; }else{ ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ int bRecursive; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 | Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ u8 jointype; /* Type of join between this able and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ #ifndef SQLITE_OMIT_EXPLAIN u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ #endif int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ | > | 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 | Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ u8 jointype; /* Type of join between this able and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ #ifndef SQLITE_OMIT_EXPLAIN u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ #endif int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ |
︙ | ︙ |
Changes to test/with1.test.
︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 | /etc/rc.d/rc.apache /etc/rc.d/rc.samba /home /home/dan /home/dan/public_html /home/dan/public_html/index.html /home/dan/public_html/index.html/logo.gif } finish_test | > > > > > > > > > > > > > > > > > > > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | /etc/rc.d/rc.apache /etc/rc.d/rc.samba /home /home/dan /home/dan/public_html /home/dan/public_html/index.html /home/dan/public_html/index.html/logo.gif } do_execsql_test 6.3 { WITH flat(fid, fpath) AS ( SELECT id, '' FROM f WHERE parentid IS NULL UNION ALL SELECT id, fpath || '/' || name FROM f, flat WHERE parentid=+fid ) SELECT count(*) FROM flat; } {15} do_execsql_test 6.4 { WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<10 ) SELECT count(*) FROM x } {10} finish_test |