/ Check-in [61be2da0]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | common-table-expr
Files: files | file ages | folders
SHA1: 61be2da0ae623c1572819481508b044e9d32f294
User & Date: dan 2014-01-15 18:12:00
Context
2014-01-15
18:21
Disable automatic indices on recursive CTE references. check-in: 28aa6db8 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: 61be2da0 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: 9a514b50 user: dan tags: common-table-expr
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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