/ Check-in [088009efdd]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a bug in CTE handling discovered by LibFuzzer that can cause an infinite loop in the query planner.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 088009efdd56160bb4eee0fbd829a529b141274e
User & Date: dan 2015-11-07 18:07:15
Context
2015-11-07
18:32
Enhance the sqldiff utility to deal gracefully with ALTER TABLE ADD COLUMN. (check-in: 7ea036ac37 user: drh tags: trunk)
18:07
Fix a bug in CTE handling discovered by LibFuzzer that can cause an infinite loop in the query planner. (check-in: 088009efdd user: dan tags: trunk)
17:51
Add test cases for WITH clauses. (Closed-Leaf check-in: e7e65c7559 user: dan tags: infinite-with-loop-bug)
01:19
The OPFLAG_SEEKEQ optimization is only applicable to equality comparisons against an index, not against a rowid table. (check-in: 0f5b147d1f user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/select.c.

3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
** then return a pointer to the CTE definition for that table. Otherwise
** return NULL.
**
** If a non-NULL value is returned, set *ppContext to point to the With
** object that the returned CTE belongs to.
*/
static struct Cte *searchWith(
  With *pWith,                    /* Current outermost WITH clause */
  struct SrcList_item *pItem,     /* FROM clause element to resolve */
  With **ppContext                /* OUT: WITH clause return value belongs to */
){
  const char *zName;
  if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
    With *p;
    for(p=pWith; p; p=p->pOuter){







|







3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
** then return a pointer to the CTE definition for that table. Otherwise
** return NULL.
**
** If a non-NULL value is returned, set *ppContext to point to the With
** object that the returned CTE belongs to.
*/
static struct Cte *searchWith(
  With *pWith,                    /* Current innermost WITH clause */
  struct SrcList_item *pItem,     /* FROM clause element to resolve */
  With **ppContext                /* OUT: WITH clause return value belongs to */
){
  const char *zName;
  if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
    With *p;
    for(p=pWith; p; p=p->pOuter){
3999
4000
4001
4002
4003
4004
4005
4006
4007

4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
** onto the top of the stack. If argument bFree is true, then this
** WITH clause will never be popped from the stack. In this case it
** should be freed along with the Parse object. In other cases, when
** bFree==0, the With object will be freed along with the SELECT 
** statement with which it is associated.
*/
void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
  assert( bFree==0 || pParse->pWith==0 );
  if( pWith ){

    pWith->pOuter = pParse->pWith;
    pParse->pWith = pWith;
    pParse->bFreeWith = bFree;
  }
}

/*
** 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







|

>


|







3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
** onto the top of the stack. If argument bFree is true, then this
** WITH clause will never be popped from the stack. In this case it
** should be freed along with the Parse object. In other cases, when
** bFree==0, the With object will be freed along with the SELECT 
** statement with which it is associated.
*/
void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
  assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
  if( pWith ){
    assert( pParse->pWith!=pWith );
    pWith->pOuter = pParse->pWith;
    pParse->pWith = pWith;
    if( bFree ) pParse->pWithToFree = pWith;
  }
}

/*
** 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
4096
4097
4098
4099
4100
4101
4102

4103
4104
4105
4106
4107
4108
4109
    }
    assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));

    pCte->zCteErr = "circular reference: %s";
    pSavedWith = pParse->pWith;
    pParse->pWith = pWith;
    sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);


    for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
    pEList = pLeft->pEList;
    if( pCte->pCols ){
      if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
        sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
            pCte->zName, pEList->nExpr, pCte->pCols->nExpr







>







4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
    }
    assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));

    pCte->zCteErr = "circular reference: %s";
    pSavedWith = pParse->pWith;
    pParse->pWith = pWith;
    sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
    pParse->pWith = pWith;

    for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
    pEList = pLeft->pEList;
    if( pCte->pCols ){
      if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){
        sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns",
            pCte->zName, pEList->nExpr, pCte->pCols->nExpr

Changes to src/sqliteInt.h.

2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
  ** using offsetof(Parse,nVar) so the nVar field must be the first field
  ** in the recursive region.
  ************************************************************************/

  int nVar;                 /* Number of '?' variables seen in the SQL so far */
  int nzVar;                /* Number of available slots in azVar[] */
  u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */
  u8 bFreeWith;             /* True if pWith should be freed with parser */
  u8 explain;               /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
  int nVtabLock;            /* Number of virtual tables to lock */
#endif
  int nAlias;               /* Number of aliased result set columns */
  int nHeight;              /* Expression tree height of current sub-select */







<







2750
2751
2752
2753
2754
2755
2756

2757
2758
2759
2760
2761
2762
2763
  ** using offsetof(Parse,nVar) so the nVar field must be the first field
  ** in the recursive region.
  ************************************************************************/

  int nVar;                 /* Number of '?' variables seen in the SQL so far */
  int nzVar;                /* Number of available slots in azVar[] */
  u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */

  u8 explain;               /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
  int nVtabLock;            /* Number of virtual tables to lock */
#endif
  int nAlias;               /* Number of aliased result set columns */
  int nHeight;              /* Expression tree height of current sub-select */
2777
2778
2779
2780
2781
2782
2783

2784
2785
2786
2787
2788
2789
2790
#ifndef SQLITE_OMIT_VIRTUALTABLE
  Token sArg;               /* Complete text of a module argument */
  Table **apVtabLock;       /* Pointer to virtual tables needing locking */
#endif
  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 */

};

/*
** Return true if currently inside an sqlite3_declare_vtab() call.
*/
#ifdef SQLITE_OMIT_VIRTUALTABLE
  #define IN_DECLARE_VTAB 0







>







2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
#ifndef SQLITE_OMIT_VIRTUALTABLE
  Token sArg;               /* Complete text of a module argument */
  Table **apVtabLock;       /* Pointer to virtual tables needing locking */
#endif
  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 */
  With *pWithToFree;        /* Free this WITH object at the end of the parse */
};

/*
** Return true if currently inside an sqlite3_declare_vtab() call.
*/
#ifdef SQLITE_OMIT_VIRTUALTABLE
  #define IN_DECLARE_VTAB 0
3267
3268
3269
3270
3271
3272
3273

3274
3275
3276
3277
3278
3279
3280
  void *sqlite3TestTextToPtr(const char*);
#endif

#if defined(SQLITE_DEBUG)
  void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
  void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
  void sqlite3TreeViewSelect(TreeView*, const Select*, u8);

#endif


void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
int sqlite3Dequote(char*);
int sqlite3KeywordCode(const unsigned char*, int);







>







3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
  void *sqlite3TestTextToPtr(const char*);
#endif

#if defined(SQLITE_DEBUG)
  void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
  void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
  void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
  void sqlite3TreeViewWith(TreeView*, const With*, u8);
#endif


void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
int sqlite3Dequote(char*);
int sqlite3KeywordCode(const unsigned char*, int);

Changes to src/tokenize.c.

506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
    /* If the pParse->declareVtab flag is set, do not delete any table 
    ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
    ** will take responsibility for freeing the Table structure.
    */
    sqlite3DeleteTable(db, pParse->pNewTable);
  }

  if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith);
  sqlite3DeleteTrigger(db, pParse->pNewTrigger);
  for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
  sqlite3DbFree(db, pParse->azVar);
  while( pParse->pAinc ){
    AutoincInfo *p = pParse->pAinc;
    pParse->pAinc = p->pNext;
    sqlite3DbFree(db, p);







|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
    /* If the pParse->declareVtab flag is set, do not delete any table 
    ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
    ** will take responsibility for freeing the Table structure.
    */
    sqlite3DeleteTable(db, pParse->pNewTable);
  }

  sqlite3WithDelete(db, pParse->pWithToFree);
  sqlite3DeleteTrigger(db, pParse->pNewTrigger);
  for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
  sqlite3DbFree(db, pParse->azVar);
  while( pParse->pAinc ){
    AutoincInfo *p = pParse->pAinc;
    pParse->pAinc = p->pNext;
    sqlite3DbFree(db, p);

Changes to src/treeview.c.

75
76
77
78
79
80
81







































82
83
84
85
86
87
88
89





90
91
92
93
94
95
96
** Shorthand for starting a new tree item that consists of a single label
*/
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
  p = sqlite3TreeViewPush(p, moreFollows);
  sqlite3TreeViewLine(p, "%s", zLabel);
}









































/*
** Generate a human-readable description of a the Select object.
*/
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
  int n = 0;
  int cnt = 0;
  pView = sqlite3TreeViewPush(pView, moreToFollow);





  do{
    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
    );
    if( cnt++ ) sqlite3TreeViewPop(pView);
    if( p->pPrior ){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>
>
>
>
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
** Shorthand for starting a new tree item that consists of a single label
*/
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
  p = sqlite3TreeViewPush(p, moreFollows);
  sqlite3TreeViewLine(p, "%s", zLabel);
}

/*
** Generate a human-readable description of a WITH clause.
*/
void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
  int i;
  if( pWith==0 ) return;
  if( pWith->nCte==0 ) return;
  if( pWith->pOuter ){
    sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter);
  }else{
    sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
  }
  if( pWith->nCte>0 ){
    pView = sqlite3TreeViewPush(pView, 1);
    for(i=0; i<pWith->nCte; i++){
      StrAccum x;
      char zLine[1000];
      const struct Cte *pCte = &pWith->a[i];
      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
      sqlite3XPrintf(&x, 0, "%s", pCte->zName);
      if( pCte->pCols && pCte->pCols->nExpr>0 ){
        char cSep = '(';
        int j;
        for(j=0; j<pCte->pCols->nExpr; j++){
          sqlite3XPrintf(&x, 0, "%c%s", cSep, pCte->pCols->a[j].zName);
          cSep = ',';
        }
        sqlite3XPrintf(&x, 0, ")");
      }
      sqlite3XPrintf(&x, 0, " AS");
      sqlite3StrAccumFinish(&x);
      sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
      sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
      sqlite3TreeViewPop(pView);
    }
    sqlite3TreeViewPop(pView);
  }
}


/*
** Generate a human-readable description of a the Select object.
*/
void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
  int n = 0;
  int cnt = 0;
  pView = sqlite3TreeViewPush(pView, moreToFollow);
  if( p->pWith ){
    sqlite3TreeViewWith(pView, p->pWith, 1);
    cnt = 1;
    sqlite3TreeViewPush(pView, 1);
  }
  do{
    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
    );
    if( cnt++ ) sqlite3TreeViewPop(pView);
    if( p->pPrior ){

Changes to test/with1.test.

860
861
862
863
864
865
866














































































































867
868
# 2015-07-05:  Do not allow aggregate recursive queries
#
do_catchsql_test 16.1 {
  WITH RECURSIVE
    i(x) AS (VALUES(1) UNION SELECT count(*) FROM i)
  SELECT * FROM i;
} {1 {recursive aggregate queries not supported}}















































































































finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
# 2015-07-05:  Do not allow aggregate recursive queries
#
do_catchsql_test 16.1 {
  WITH RECURSIVE
    i(x) AS (VALUES(1) UNION SELECT count(*) FROM i)
  SELECT * FROM i;
} {1 {recursive aggregate queries not supported}}

#-------------------------------------------------------------------------
do_execsql_test 17.1 {
  WITH x(a) AS (
    WITH y(b) AS (SELECT 10)
    SELECT 9 UNION ALL SELECT * FROM y
  )
  SELECT * FROM x
} {9 10}

do_execsql_test 17.2 {
  WITH x AS (
    WITH y(b) AS (SELECT 10)
    SELECT * FROM y UNION ALL SELECT * FROM y
  )
  SELECT * FROM x
} {10 10}

do_test 17.2 {
  db eval {
    WITH x AS (
        WITH y(b) AS (SELECT 10)
        SELECT * FROM y UNION ALL SELECT * FROM y
    )
    SELECT * FROM x
  } A {
    # no op
  }
  set A(*)
} {b}

do_catchsql_test 17.3 {
  WITH i AS (
    WITH j AS (SELECT 5)
    SELECT 5 FROM i UNION SELECT 8 FROM i
  )
  SELECT * FROM i;
} {1 {circular reference: i}}

do_catchsql_test 17.4 {
  WITH i AS (
    WITH j AS (SELECT 5)
    SELECT 5 FROM t1 UNION SELECT 8 FROM t11
  )
  SELECT * FROM i;
} {1 {no such table: t11}}

do_execsql_test 17.5 {
  WITH 
  x1 AS (SELECT 10),
  x2 AS (SELECT * FROM x1),
  x3 AS (
    WITH x1 AS (SELECT 11)
    SELECT * FROM x2 UNION ALL SELECT * FROM x2
  )
  SELECT * FROM x3;
} {10 10}

do_execsql_test 17.6 {
  WITH 
  x1 AS (SELECT 10),
  x2 AS (SELECT * FROM x1),
  x3 AS (
    WITH x1 AS (SELECT 11)
    SELECT * FROM x2 UNION ALL SELECT * FROM x1
  )
  SELECT * FROM x3;
} {10 11}

do_execsql_test 17.7 {
  WITH 
  x1 AS (SELECT 10),
  x2 AS (SELECT * FROM x1),
  x3 AS (
    WITH 
      x1 AS ( SELECT 11 ),
      x4 AS ( SELECT * FROM x2 )
    SELECT * FROM x4 UNION ALL SELECT * FROM x1
  )
  SELECT * FROM x3;
} {10 11}

do_execsql_test 17.8 {
  WITH 
  x1 AS (SELECT 10),
  x2 AS (SELECT * FROM x1),
  x3 AS (
    WITH 
      x1 AS ( SELECT 11 ),
      x4 AS ( SELECT * FROM x2 )
    SELECT * FROM x4 UNION ALL SELECT * FROM x1
  )
  SELECT * FROM x3;
} {10 11}

do_execsql_test 17.9 {
  WITH 
  x1 AS (SELECT 10),
  x2 AS (SELECT 11),
  x3 AS (
    SELECT * FROM x1 UNION ALL SELECT * FROM x2
  ),
  x4 AS (
    WITH 
    x1 AS (SELECT 12),
    x2 AS (SELECT 13)
    SELECT * FROM x3
  )
  SELECT * FROM x4;
} {10 11}

finish_test

Added test/with3.test.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 2015-11-07
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the WITH clause.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix with3

ifcapable {!cte} {
  finish_test
  return
}

# Test problems found by Kostya Serebryany using 
# LibFuzzer.  (http://llvm.org/docs/LibFuzzer.html)
#
do_catchsql_test 1.0 {
  WITH i(x) AS (
    WITH j AS (SELECT 10)
    SELECT 5 FROM t0 UNION SELECT 8 FROM m
  )
  SELECT * FROM i;
} {1 {no such table: m}}

# Additional test cases that came out of the work to
# fix for Kostya's problem.
#
do_execsql_test 2.0 {
 WITH
  x1 AS (SELECT 10),
  x2 AS (SELECT 11),
  x3 AS (
    SELECT * FROM x1 UNION ALL SELECT * FROM x2
  ),
  x4 AS (
    WITH
    x1 AS (SELECT 12),
    x2 AS (SELECT 13)
    SELECT * FROM x3
  )
  SELECT * FROM x4;

} {10 11}

do_execsql_test 2.1 {
  CREATE TABLE t1(x);
  WITH
    x1(a) AS (values(100))
  INSERT INTO t1(x)
    SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2);
  SELECT * FROM t1;
} {200}

finish_test