]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix some problems to do with WITH clauses and name resolution. common-table-expr
authordan <dan@noemail.net>
Fri, 17 Jan 2014 14:59:27 +0000 (14:59 +0000)
committerdan <dan@noemail.net>
Fri, 17 Jan 2014 14:59:27 +0000 (14:59 +0000)
FossilOrigin-Name: 6a549187ed8b5ed50daefa676ff666ae2ed43346

manifest
manifest.uuid
src/parse.y
src/select.c
src/sqliteInt.h
src/tokenize.c
src/walker.c
test/with2.test [new file with mode: 0644]

index 5d2226d267f2826742b4e87fa48f319a1fc0c6d9..586f354eacd15a7763f096eb2b18f99b92e6377e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\ssome\scode\sfrom\sresolve.c\sthat\swas\sonly\srequired\sfor\srecursive\scte\sreferences\sin\ssub-queries.\sAlso\sa\sstray\s"finish_test"\scommand\sin\spagerfault.test.
-D 2014-01-17T11:48:24.294
+C Fix\ssome\sproblems\sto\sdo\swith\sWITH\sclauses\sand\sname\sresolution.
+D 2014-01-17T14:59:27.898
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -209,7 +209,7 @@ F src/os_unix.c 3a4dcb554d3c915075766162f28c3fd4cdb75968
 F src/os_win.c 1b21af72c5fa6f9e519a5fcab33e80d182b1aedb
 F src/pager.c efa923693e958696eee69b205a20bfbc402c8480
 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
-F src/parse.y 824eeb752c026b551bda2b66163889d7664b42e4
+F src/parse.y 475896cb883bbf4782e98abda42efbbdcbdb75f5
 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b
@@ -219,12 +219,12 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
 F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c 65c13f22edfd6af04829439955c7cf5749ea4e87
+F src/select.c c77955f93121adc8b4b43a98add62fbaa2b48132
 F src/shell.c 9f3bc02a658b8f61d2cbe60cfc482f660c1c6c48
 F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h d49c0bea5282f15c1eb1eb9d705770f70d19c1e2
+F src/sqliteInt.h 9600eeb486c274fbdb815d040e4a7f262b7317e1
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -274,7 +274,7 @@ F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
 F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
 F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
-F src/tokenize.c 7dc42e9beb8c3263b79d10c195b3f5264b5f874a
+F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
 F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98
 F src/update.c c2706a6eb232a96345c35b7e1e75a188e26812bb
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
@@ -292,7 +292,7 @@ F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
-F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
+F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
 F src/where.c 369b0259fabfb22644d197736ae622f762cbaba8
 F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1092,6 +1092,7 @@ F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
 F test/with1.test 90490c75e98e1914d84b7cef9e636b48917a020f
+F test/with2.test 790c4b7ab3f4eb6984a3bbdae8d4ab429ebe9259
 F test/withM.test 52448ce23e1c2ecba79d10e130ee49ce9f9a2a7a
 F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
@@ -1150,7 +1151,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 9efc120a1548c03f3d8aabbadf1050ff2a119c31
-R 175ad2c9f66168be6fabd0b7fdb44bd2
+P f68c6c4d36481526a9348244adc571ea282dc9eb
+R d73fd639096ae3d6dc6dd6a7018ffc11
 U dan
-Z 6e3919f2cc39eeea18a32475675bdfc0
+Z 6339477b00dd8c67441747d0ac03cfea
index 6e22de7d56574d4671e1288c3ce36ac5b171c9a7..71dd74abb9b1ec799ad9ec01e609fd174d41fc04 100644 (file)
@@ -1 +1 @@
-f68c6c4d36481526a9348244adc571ea282dc9eb
\ No newline at end of file
+6a549187ed8b5ed50daefa676ff666ae2ed43346
\ No newline at end of file
index 937669eb5c4dfd7973c8643340421a9d046d600e..08054079206fa96cc129d75edf88de8023556ab9 100644 (file)
@@ -661,7 +661,7 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
 %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
 cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W) 
         orderby_opt(O) limit_opt(L). {
-  sqlite3WithPush(pParse,C);
+  sqlite3WithPush(pParse, C, 1);
   sqlite3SrcListIndexedBy(pParse, X, &I);
   W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE");
   sqlite3DeleteFrom(pParse,X,W);
@@ -669,7 +669,7 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W)
 %endif
 %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
 cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
-  sqlite3WithPush(pParse,C);
+  sqlite3WithPush(pParse, C, 1);
   sqlite3SrcListIndexedBy(pParse, X, &I);
   sqlite3DeleteFrom(pParse,X,W);
 }
@@ -686,7 +686,7 @@ where_opt(A) ::= WHERE expr(X).       {A = X.pExpr;}
 %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
 cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
         where_opt(W) orderby_opt(O) limit_opt(L).  {
-  sqlite3WithPush(pParse, C);
+  sqlite3WithPush(pParse, C, 1);
   sqlite3SrcListIndexedBy(pParse, X, &I);
   sqlite3ExprListCheckLength(pParse,Y,"set list"); 
   W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
@@ -696,7 +696,7 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
 %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
 cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
         where_opt(W).  {
-  sqlite3WithPush(pParse, C);
+  sqlite3WithPush(pParse, C, 1);
   sqlite3SrcListIndexedBy(pParse, X, &I);
   sqlite3ExprListCheckLength(pParse,Y,"set list"); 
   sqlite3Update(pParse,X,Y,W,R);
@@ -718,12 +718,12 @@ setlist(A) ::= nm(X) EQ expr(Y). {
 ////////////////////////// The INSERT command /////////////////////////////////
 //
 cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). {
-  sqlite3WithPush(pParse, W);
+  sqlite3WithPush(pParse, W, 1);
   sqlite3Insert(pParse, X, S, F, R);
 }
 cmd ::= with(W) insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
 {
-  sqlite3WithPush(pParse, W);
+  sqlite3WithPush(pParse, W, 1);
   sqlite3Insert(pParse, X, 0, F, R);
 }
 
index dc784b3b10d34a6d6ea05ce82e0841b41def071b..d9625cba43cfa2d1d764039a911044d9e1495da4 100644 (file)
@@ -3527,12 +3527,19 @@ static struct Cte *searchWith(With *pWith, struct SrcList_item *pItem){
 /* The code generator maintains a stack of active WITH clauses
 ** with the inner-most WITH clause being at the top of the stack.
 **
-** These routines push and pull WITH clauses on the stack.
+** This routine pushes the WITH clause passed as the second argument
+** 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){
+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;
   }
 }
 
@@ -3649,6 +3656,19 @@ static int withExpand(
 }
 #endif
 
+#ifndef SQLITE_OMIT_CTE
+static void selectPopWith(Walker *pWalker, Select *p){
+  Parse *pParse = pWalker->pParse;
+  if( p->pWith ){
+    assert( pParse->pWith==p->pWith );
+    pParse->pWith = p->pWith->pOuter;
+  }
+  return WRC_Continue;
+}
+#else
+#define selectPopWith 0
+#endif
+
 /*
 ** This routine is a Walker callback for "expanding" a SELECT statement.
 ** "Expanding" means to do the following:
@@ -3692,6 +3712,7 @@ static int selectExpander(Walker *pWalker, Select *p){
   }
   pTabList = p->pSrc;
   pEList = p->pEList;
+  sqlite3WithPush(pParse, p->pWith, 0);
 
   /* Make sure cursor numbers have been assigned to all entries in
   ** the FROM clause of the SELECT statement.
@@ -3710,6 +3731,9 @@ static int selectExpander(Walker *pWalker, Select *p){
       /* This statement has already been prepared.  There is no need
       ** to go further. */
       assert( i==0 );
+#ifndef SQLITE_OMIT_CTE
+      selectPopWith(pWalker, p);
+#endif
       return WRC_Prune;
     }
 #ifndef SQLITE_OMIT_CTE
@@ -3941,30 +3965,6 @@ static int selectExpander(Walker *pWalker, Select *p){
   return WRC_Continue;
 }
 
-/*
-** Function (or macro) selectExpanderWith is used as the SELECT callback
-** by sqlite3SelectExpand(). In builds that do not support CTEs, this
-** is equivalent to the selectExpander() function. In CTE-enabled builds,
-** any WITH clause associated with the SELECT statement needs to be
-** pushed onto the stack before calling selectExpander(), and popped
-** off again afterwards. 
-*/
-#ifndef SQLITE_OMIT_CTE
-static int selectExpanderWith(Walker *pWalker, Select *p){
-  Parse *pParse = pWalker->pParse;
-  int res;
-  sqlite3WithPush(pParse, p->pWith);
-  res = selectExpander(pWalker, p);
-  if( p->pWith ){
-    assert( pParse->pWith==p->pWith );
-    pParse->pWith = p->pWith->pOuter;
-  }
-  return res;
-}
-#else
-#define selectExpanderWith selectExpander
-#endif
-
 /*
 ** No-op routine for the parse-tree walker.
 **
@@ -4001,7 +4001,8 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
     w.xSelectCallback = convertCompoundSelectToSubquery;
     sqlite3WalkSelect(&w, pSelect);
   }
-  w.xSelectCallback = selectExpanderWith;
+  w.xSelectCallback = selectExpander;
+  w.xSelectCallback2 = selectPopWith;
   sqlite3WalkSelect(&w, pSelect);
 }
 
@@ -4020,7 +4021,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
 ** at that point because identifiers had not yet been resolved.  This
 ** routine is called after identifier resolution.
 */
-static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
+static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
   Parse *pParse;
   int i;
   SrcList *pTabList;
@@ -4043,7 +4044,6 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
       }
     }
   }
-  return WRC_Continue;
 }
 #endif
 
@@ -4059,10 +4059,9 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
 #ifndef SQLITE_OMIT_SUBQUERY
   Walker w;
   memset(&w, 0, sizeof(w));
-  w.xSelectCallback = selectAddSubqueryTypeInfo;
+  w.xSelectCallback2 = selectAddSubqueryTypeInfo;
   w.xExprCallback = exprWalkNoop;
   w.pParse = pParse;
-  w.bSelectDepthFirst = 1;
   sqlite3WalkSelect(&w, pSelect);
 #endif
 }
index 3f29f58d4e1ccf31418da1fa5f763b1516459b5f..1cdaf09dc793ccf8bc907342e9d1248a6d47dfb3 100644 (file)
@@ -2371,6 +2371,7 @@ 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 */
+  u8 bFreeWith;             /* True if pWith should be freed with parser */
 };
 
 /*
@@ -2612,9 +2613,9 @@ struct Sqlite3Config {
 struct Walker {
   int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */
   int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
+  void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
   Parse *pParse;                            /* Parser context.  */
   int walkerDepth;                          /* Number of subqueries */
-  u8 bSelectDepthFirst;                     /* Do subqueries first */
   union {                                   /* Extra data for callback */
     NameContext *pNC;                          /* Naming context */
     int i;                                     /* Integer value */
@@ -3354,9 +3355,9 @@ const char *sqlite3JournalModename(int);
 #ifndef SQLITE_OMIT_CTE
   With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
   void sqlite3WithDelete(sqlite3*,With*);
-  void sqlite3WithPush(Parse*, With*);
+  void sqlite3WithPush(Parse*, With*, u8);
 #else
-#define sqlite3WithPush(x,y)
+#define sqlite3WithPush(x,y,z)
 #define sqlite3WithDelete(x,y)
 #endif
 
index 3fd4f78f7a5ff0597e140f6eca202c0675b1ee3c..87553e25b049419a5c76e4944a29f7989353ef5d 100644 (file)
@@ -494,8 +494,7 @@ abort_parse:
     sqlite3DeleteTable(db, pParse->pNewTable);
   }
 
-  assert( pParse->pWith==0 || pParse->pWith->pOuter==0 );
-  sqlite3WithDelete(db, pParse->pWith);
+  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);
index cde34ad78031a3a7a265cdc7ad73a82120d38535..016ae77a92be39b809ee7b8146b4d52df2725941 100644 (file)
@@ -113,9 +113,12 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
 /*
 ** Call sqlite3WalkExpr() for every expression in Select statement p.
 ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
-** on the compound select chain, p->pPrior.  Invoke the xSelectCallback()
-** either before or after the walk of expressions and FROM clause, depending
-** on whether pWalker->bSelectDepthFirst is false or true, respectively.
+** on the compound select chain, p->pPrior. 
+**
+** If it is not NULL, the xSelectCallback() callback is invoked before
+** the walk of the expressions and FROM clause. The xSelectCallback2()
+** method, if it is not NULL, is invoked following the walk of the 
+** expressions and FROM clause.
 **
 ** Return WRC_Continue under normal conditions.  Return WRC_Abort if
 ** there is an abort request.
@@ -125,11 +128,13 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
 */
 int sqlite3WalkSelect(Walker *pWalker, Select *p){
   int rc;
-  if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue;
+  if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
+    return WRC_Continue;
+  }
   rc = WRC_Continue;
   pWalker->walkerDepth++;
   while( p ){
-    if( !pWalker->bSelectDepthFirst ){
+    if( pWalker->xSelectCallback ){
        rc = pWalker->xSelectCallback(pWalker, p);
        if( rc ) break;
     }
@@ -139,12 +144,8 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){
       pWalker->walkerDepth--;
       return WRC_Abort;
     }
-    if( pWalker->bSelectDepthFirst ){
-      rc = pWalker->xSelectCallback(pWalker, p);
-      /* Depth-first search is currently only used for
-      ** selectAddSubqueryTypeInfo() and that routine always returns
-      ** WRC_Continue (0).  So the following branch is never taken. */
-      if( NEVER(rc) ) break;
+    if( pWalker->xSelectCallback2 ){
+      pWalker->xSelectCallback2(pWalker, p);
     }
     p = p->pPrior;
   }
diff --git a/test/with2.test b/test/with2.test
new file mode 100644 (file)
index 0000000..83b3b73
--- /dev/null
@@ -0,0 +1,56 @@
+# 2014 January 11
+#
+# 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 with2
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a);
+  INSERT INTO t1 VALUES(1);
+  INSERT INTO t1 VALUES(2);
+}
+
+do_execsql_test 1.1 {
+  WITH x1 AS (SELECT * FROM t1)
+  SELECT sum(a) FROM x1;
+} {3}
+
+do_execsql_test 1.2 {
+  WITH x1 AS (SELECT * FROM t1)
+  SELECT (SELECT sum(a) FROM x1);
+} {3}
+
+do_execsql_test 1.3 {
+  WITH x1 AS (SELECT * FROM t1)
+  SELECT (SELECT sum(a) FROM x1);
+} {3}
+
+do_execsql_test 1.4 {
+  CREATE TABLE t2(i);
+  INSERT INTO t2 VALUES(2);
+  INSERT INTO t2 VALUES(3);
+  INSERT INTO t2 VALUES(5);
+
+  WITH x1   AS (SELECT i FROM t2),
+       i(a) AS (
+         SELECT min(i)-1 FROM x1 UNION SELECT a+1 FROM i WHERE a<10
+       )
+  SELECT a FROM i WHERE a NOT IN x1
+} {1 4 6 7 8 9 10}
+
+finish_test
+
+
+