]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test cases and fix bugs associated with the previous check-in nested-agg
authordrh <drh@noemail.net>
Thu, 23 Aug 2012 19:46:11 +0000 (19:46 +0000)
committerdrh <drh@noemail.net>
Thu, 23 Aug 2012 19:46:11 +0000 (19:46 +0000)
enhancements to nested aggregate subquery processing.

FossilOrigin-Name: 00b1dc71be4c3420730b5f7840af824ea86165e7

manifest
manifest.uuid
src/expr.c
src/resolve.c
src/walker.c
test/aggnested.test

index a43f6d1a8ff3487068845ae329af800cce926fad..e26aaf6a30a475499d60e14375de4d02da8f0a7b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Further\simprovements\sto\sthe\sprocessing\sof\snested\saggregate\squeries.
-D 2012-08-23T16:18:10.544
+C Add\stest\scases\sand\sfix\sbugs\sassociated\swith\sthe\sprevious\scheck-in\nenhancements\sto\snested\saggregate\ssubquery\sprocessing.
+D 2012-08-23T19:46:11.832
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in abd5c10d21d1395f140d9e50ea999df8fa4d6376
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -132,7 +132,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 500d019da966631ad957c37705642be87524463b
 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
 F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e
-F src/expr.c e03a5509b5c8f0d0b5e8210ea43addabc4a17f47
+F src/expr.c 94bac8cc555d97fe4518529ad53d9ba926df9d62
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
 F src/func.c 18dfedfb857e100b05755a1b12e88b389f957879
@@ -174,7 +174,7 @@ F src/pragma.c 97f9357f0e7e5fb46a2519f14539550aa07db49f
 F src/prepare.c 33291b83cca285718048d219c67b8298501fa3a5
 F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
-F src/resolve.c e60d1f7ce1f1d1ae13acf1c39b4e8bfd9e243847
+F src/resolve.c 9e28280ec98035f31900fdd1db01f86f68ca6c32
 F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
 F src/select.c cd051b460e7d0c3ac42e7727eef075fb29c23769
 F src/shell.c 076e1c90d594644f36027c8ecff9a392cf2d3a06
@@ -249,11 +249,11 @@ F src/vdbetrace.c 8bd5da325fc90f28464335e4cc4ad1407fe30835
 F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998
 F src/wal.c 9294df6f96aae5909ae1a9b733fd1e1b4736978b
 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
-F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
+F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
 F src/where.c 24c7494d8875ead994b4dfe5461340c27fd424ca
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
-F test/aggnested.test 6c1efa2ed9f5dd0f80035b4fe794c6a278cd1ead
+F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748
@@ -1012,10 +1012,7 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
-P b1dbf490869d7fc55ce797cf80cf3bf7141d2d15
-R 6f0858104ecac7c70bd80af9dbc9e718
-T *branch * nested-agg
-T *sym-nested-agg *
-T -sym-trunk *
+P 3c3ffa901f5ce8a523028ff15563ce3e0f55a641
+R 7ac9abcbd2554a39d90c74812c59041d
 U drh
-Z fbb7622480ad2005f08fba3df589ccf6
+Z 5534967a0ee04b7aa372747f5ce8ed30
index 3c6db4542e845bf2ed99176fbf7640dd3de01b43..e2e4740fdd8c7c1f04228f1359edba1a7a0a1875 100644 (file)
@@ -1 +1 @@
-3c3ffa901f5ce8a523028ff15563ce3e0f55a641
\ No newline at end of file
+00b1dc71be4c3420730b5f7840af824ea86165e7
\ No newline at end of file
index e2f8b4578625e412a52bf807c384136e57af4965..9fe899402352870ecea3ddcfbbe676fd9748c6f7 100644 (file)
@@ -3123,9 +3123,12 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
       }else{
         pFarg = pExpr->x.pList;
       }
-      sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(",
-                           op==TK_AGG_FUNCTION ? "AGG_" : "",
-                           pExpr->u.zToken);
+      if( op==TK_AGG_FUNCTION ){
+        sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(",
+                             pExpr->op2, pExpr->u.zToken);
+      }else{
+        sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken);
+      }
       if( pFarg ){
         sqlite3ExplainExprList(pOut, pFarg);
       }
@@ -3818,8 +3821,8 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
 /*
 ** An instance of the following structure is used by the tree walker
 ** to count references to table columns in the arguments of an 
-** aggregate function, in order to implement the sqlite3FunctionUsesOtherSrc()
-** and sqlite3FunctionThisSrc() routines.
+** aggregate function, in order to implement the
+** sqlite3FunctionThisSrc() routine.
 */
 struct SrcCount {
   SrcList *pSrc;   /* One particular FROM clause in a nested query */
@@ -3847,26 +3850,6 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
   return WRC_Continue;
 }
 
-/*
-** Determine if any of the arguments to the pExpr Function references
-** any SrcList other than pSrcList.  Return true if they do.  Return
-** false if pExpr has no argument or has only constant arguments or
-** only references tables named in pSrcList.
-*/
-static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){
-  Walker w;
-  struct SrcCount cnt;
-  assert( pExpr->op==TK_AGG_FUNCTION );
-  memset(&w, 0, sizeof(w));
-  w.xExprCallback = exprSrcCount;
-  w.u.pSrcCount = &cnt;
-  cnt.pSrc = pSrcList;
-  cnt.nThis = 0;
-  cnt.nOther = 0;
-  sqlite3WalkExprList(&w, pExpr->x.pList);
-  return cnt.nOther>0;
-}
-
 /*
 ** Determine if any of the arguments to the pExpr Function reference
 ** pSrcList.  Return true if they do.  Also return true if the function
@@ -4003,7 +3986,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
     }
     case TK_AGG_FUNCTION: {
       if( (pNC->ncFlags & NC_InAggFunc)==0
-       && !sqlite3FunctionUsesOtherSrc(pExpr, pSrcList)
+       && pWalker->walkerDepth==pExpr->op2
       ){
         /* Check to see if pExpr is a duplicate of another aggregate 
         ** function that is already in the pAggInfo structure
index bfbcd20419b8f27c951aa0aa001be5c8fea32c3c..b87d231ac2eb57dec51b3c7142efd0a7455b688e 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+/*
+** Walk the expression tree pExpr and increase the aggregate function
+** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
+** This needs to occur when copying a TK_AGG_FUNCTION node from an
+** outer query into an inner subquery.
+**
+** incrAggFunctionDepth(pExpr,n) is the main routine.  incrAggDepth(..)
+** is a helper function - a callback for the tree walker.
+*/
+static int incrAggDepth(Walker *pWalker, Expr *pExpr){
+  if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i;
+  return WRC_Continue;
+}
+static void incrAggFunctionDepth(Expr *pExpr, int N){
+  if( N>0 ){
+    Walker w;
+    memset(&w, 0, sizeof(w));
+    w.xExprCallback = incrAggDepth;
+    w.u.i = N;
+    sqlite3WalkExpr(&w, pExpr);
+  }
+}
+
 /*
 ** Turn the pExpr expression into an alias for the iCol-th column of the
 ** result set in pEList.
 ** The result of random()%5 in the GROUP BY clause is probably different
 ** from the result in the result-set.  We might fix this someday.  Or
 ** then again, we might not...
+**
+** The nSubquery parameter specifies how many levels of subquery the
+** alias is removed from the original expression.  The usually value is
+** zero but it might be more if the alias is contained within a subquery
+** of the original expression.  The Expr.op2 field of TK_AGG_FUNCTION
+** structures must be increased by the nSubquery amount.
 */
 static void resolveAlias(
   Parse *pParse,         /* Parsing context */
   ExprList *pEList,      /* A result set */
   int iCol,              /* A column in the result set.  0..pEList->nExpr-1 */
   Expr *pExpr,           /* Transform this into an alias to the result set */
-  const char *zType      /* "GROUP" or "ORDER" or "" */
+  const char *zType,     /* "GROUP" or "ORDER" or "" */
+  int nSubquery          /* Number of subqueries that the label is moving */
 ){
   Expr *pOrig;           /* The iCol-th column of the result set */
   Expr *pDup;            /* Copy of pOrig */
@@ -63,6 +93,7 @@ static void resolveAlias(
   db = pParse->db;
   if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
     pDup = sqlite3ExprDup(db, pOrig, 0);
+    incrAggFunctionDepth(pDup, nSubquery);
     pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
     if( pDup==0 ) return;
     if( pEList->a[iCol].iAlias==0 ){
@@ -151,9 +182,10 @@ static int lookupName(
   NameContext *pNC,    /* The name context used to resolve the name */
   Expr *pExpr          /* Make this EXPR node point to the selected column */
 ){
-  int i, j;            /* Loop counters */
+  int i, j;                         /* Loop counters */
   int cnt = 0;                      /* Number of matching column names */
   int cntTab = 0;                   /* Number of matching table names */
+  int nSubquery = 0;                /* How many levels of subquery */
   sqlite3 *db = pParse->db;         /* The database connection */
   struct SrcList_item *pItem;       /* Use for looping over pSrcList items */
   struct SrcList_item *pMatch = 0;  /* The matching pSrcList item */
@@ -315,7 +347,7 @@ static int lookupName(
             sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
             return WRC_Abort;
           }
-          resolveAlias(pParse, pEList, j, pExpr, "");
+          resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
           cnt = 1;
           pMatch = 0;
           assert( zTab==0 && zDb==0 );
@@ -329,6 +361,7 @@ static int lookupName(
     */
     if( cnt==0 ){
       pNC = pNC->pNext;
+      nSubquery++;
     }
   }
 
@@ -859,7 +892,7 @@ int sqlite3ResolveOrderGroupBy(
         resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
         return 1;
       }
-      resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType);
+      resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType,0);
     }
   }
   return 0;
index c95a9c169db3125ad877cca14d88abd13495ac21..eab96ea24dcd6e6564e4c3fc94e28397de6620d0 100644 (file)
@@ -125,12 +125,18 @@ int sqlite3WalkSelect(Walker *pWalker, Select *p){
   int rc;
   if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue;
   rc = WRC_Continue;
-  while( p  ){
+  pWalker->walkerDepth++;
+  while( p ){
     rc = pWalker->xSelectCallback(pWalker, p);
     if( rc ) break;
-    if( sqlite3WalkSelectExpr(pWalker, p) ) return WRC_Abort;
-    if( sqlite3WalkSelectFrom(pWalker, p) ) return WRC_Abort;
+    if( sqlite3WalkSelectExpr(pWalker, p)
+     || sqlite3WalkSelectFrom(pWalker, p)
+    ){
+      pWalker->walkerDepth--;
+      return WRC_Abort;
+    }
     p = p->pPrior;
   }
+  pWalker->walkerDepth--;
   return rc & WRC_Abort;
 }
index d76398093f8226251f0493c0ccd9a317baa68407..22f0fb6b9a77a5675346909af9690698116475c2 100644 (file)
@@ -34,5 +34,38 @@ do_test aggnested-1.2 {
     FROM t1;
   }
 } {1x2x3-4y5}
+do_test aggnested-1.3 {
+  db eval {
+    SELECT (SELECT group_concat(b1,a1) FROM t2) FROM t1;
+  }
+} {415 425 435}
+do_test aggnested-1.4 {
+  db eval {
+    SELECT (SELECT group_concat(a1,b1) FROM t2) FROM t1;
+  }
+} {151 252 353}
+
+
+# This test case is a copy of the one in
+# http://www.mail-archive.com/sqlite-users@sqlite.org/msg70787.html
+#
+do_test aggnested-2.0 {
+  sqlite3 db2 :memory:
+  db2 eval {
+    CREATE TABLE t1 (A1 INTEGER NOT NULL,A2 INTEGER NOT NULL,A3 INTEGER NOT 
+    NULL,A4 INTEGER NOT NULL,PRIMARY KEY(A1));
+    REPLACE INTO t1 VALUES(1,11,111,1111);
+    REPLACE INTO t1 VALUES(2,22,222,2222);
+    REPLACE INTO t1 VALUES(3,33,333,3333);
+    CREATE TABLE t2 (B1 INTEGER NOT NULL,B2 INTEGER NOT NULL,B3 INTEGER NOT 
+    NULL,B4 INTEGER NOT NULL,PRIMARY KEY(B1));
+    REPLACE INTO t2 VALUES(1,88,888,8888);
+    REPLACE INTO t2 VALUES(2,99,999,9999);
+    SELECT (SELECT GROUP_CONCAT(CASE WHEN a1=1 THEN'A' ELSE 'B' END) FROM t2),
+            t1.* 
+    FROM t1;
+  }
+} {A,B,B 3 33 333 3333}
+db2 close
 
 finish_test