]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further improvements to the processing of nested aggregate queries.
authordrh <drh@noemail.net>
Thu, 23 Aug 2012 16:18:10 +0000 (16:18 +0000)
committerdrh <drh@noemail.net>
Thu, 23 Aug 2012 16:18:10 +0000 (16:18 +0000)
FossilOrigin-Name: 3c3ffa901f5ce8a523028ff15563ce3e0f55a641

manifest
manifest.uuid
src/expr.c
src/resolve.c
src/select.c
src/sqliteInt.h
test/aggnested.test [new file with mode: 0644]

index 796283a32df3fb42a61e97f67fe3f9e95e4dd2d8..a43f6d1a8ff3487068845ae329af800cce926fad 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Modify\sthe\sMSVC\smakefile\sto\smake\sit\seasier\sto\sselect\sthe\sheap\ssubsystem\sto\suse.
-D 2012-08-22T00:39:34.681
+C Further\simprovements\sto\sthe\sprocessing\sof\snested\saggregate\squeries.
+D 2012-08-23T16:18:10.544
 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 e2927abf9c69ce4ff9a931bd201946961c34819a
+F src/expr.c e03a5509b5c8f0d0b5e8210ea43addabc4a17f47
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
 F src/func.c 18dfedfb857e100b05755a1b12e88b389f957879
@@ -174,13 +174,13 @@ F src/pragma.c 97f9357f0e7e5fb46a2519f14539550aa07db49f
 F src/prepare.c 33291b83cca285718048d219c67b8298501fa3a5
 F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
-F src/resolve.c b3c70ab28cac60de33684c9aa9e5138dcf71d6dd
+F src/resolve.c e60d1f7ce1f1d1ae13acf1c39b4e8bfd9e243847
 F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
-F src/select.c a365da6d7a6d7d8a10ad60ca71837ab5e9369466
+F src/select.c cd051b460e7d0c3ac42e7727eef075fb29c23769
 F src/shell.c 076e1c90d594644f36027c8ecff9a392cf2d3a06
 F src/sqlite.h.in f664797c68ced43c2ea2c541d4ec8e1e04ec68ac
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
-F src/sqliteInt.h c8169801f8bbfdf5873cc6fa45cb5df720c04db4
+F src/sqliteInt.h f4748d18114510f61e6de8bac0d513dc76e8f21c
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -253,6 +253,7 @@ F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c 24c7494d8875ead994b4dfe5461340c27fd424ca
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
+F test/aggnested.test 6c1efa2ed9f5dd0f80035b4fe794c6a278cd1ead
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748
@@ -1011,7 +1012,10 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
-P 573770f5a66fa4d708931b30350149eb739da607
-R 37de98f91b94867b24c6cd4084658a36
-U mistachkin
-Z 9fc3bc40456dded5ffdcfb8030fc95c3
+P b1dbf490869d7fc55ce797cf80cf3bf7141d2d15
+R 6f0858104ecac7c70bd80af9dbc9e718
+T *branch * nested-agg
+T *sym-nested-agg *
+T -sym-trunk *
+U drh
+Z fbb7622480ad2005f08fba3df589ccf6
index 3674ab90b9d3390db1f4ee2709f81c39308e4bbe..3c6db4542e845bf2ed99176fbf7640dd3de01b43 100644 (file)
@@ -1 +1 @@
-b1dbf490869d7fc55ce797cf80cf3bf7141d2d15
\ No newline at end of file
+3c3ffa901f5ce8a523028ff15563ce3e0f55a641
\ No newline at end of file
index 790aa45f3b2dd5a43be5d0838291b876b4db72b1..e2f8b4578625e412a52bf807c384136e57af4965 100644 (file)
@@ -3816,22 +3816,35 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
 }
 
 /*
-** This is the expression callback for sqlite3FunctionUsesOtherSrc().
-**
-** Determine if an expression references any table other than one of the
-** tables in pWalker->u.pSrcList and abort if it does.
+** 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.
 */
-static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
+struct SrcCount {
+  SrcList *pSrc;   /* One particular FROM clause in a nested query */
+  int nThis;       /* Number of references to columns in pSrcList */
+  int nOther;      /* Number of references to columns in other FROM clauses */
+};
+
+/*
+** Count the number of references to columns.
+*/
+static int exprSrcCount(Walker *pWalker, Expr *pExpr){
   if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
     int i;
-    SrcList *pSrc = pWalker->u.pSrcList;
+    struct SrcCount *p = pWalker->u.pSrcCount;
+    SrcList *pSrc = p->pSrc;
     for(i=0; i<pSrc->nSrc; i++){
-      if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue;
+      if( pExpr->iTable==pSrc->a[i].iCursor ) break;
+    }
+    if( i<pSrc->nSrc ){
+      p->nThis++;
+    }else{
+      p->nOther++;
     }
-    return WRC_Abort;
-  }else{
-    return WRC_Continue;
   }
+  return WRC_Continue;
 }
 
 /*
@@ -3842,12 +3855,36 @@ static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
 */
 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 = exprUsesOtherSrc;
-  w.u.pSrcList = pSrcList;
-  if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1;
-  return 0;
+  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
+** has no arguments or has only constant arguments.  Return false if pExpr
+** references columns but not columns of tables found in pSrcList.
+*/
+int sqlite3FunctionUsesThisSrc(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.nThis>0 || cnt.nOther==0;
 }
 
 /*
index a66f88fdc0dd48b172d10e6600b599e5cfb601dd..bfbcd20419b8f27c951aa0aa001be5c8fea32c3c 100644 (file)
@@ -568,13 +568,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
              nId, zId);
         pNC->nErr++;
       }
+      if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
+      sqlite3WalkExprList(pWalker, pList);
       if( is_agg ){
+        NameContext *pNC2 = pNC;
         pExpr->op = TK_AGG_FUNCTION;
-        pNC->ncFlags |= NC_HasAgg;
+        pExpr->op2 = 0;
+        while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
+          pExpr->op2++;
+          pNC2 = pNC2->pNext;
+        }
+        if( pNC2 ) pNC2->ncFlags |= NC_HasAgg;
+        pNC->ncFlags |= NC_AllowAgg;
       }
-      if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
-      sqlite3WalkExprList(pWalker, pList);
-      if( is_agg ) pNC->ncFlags |= NC_AllowAgg;
       /* FIX ME:  Compute pExpr->affinity based on the expected return
       ** type of the function 
       */
index 491356acbb77c296ded14dfecfd7295db83cb1f4..93a084eaf23b3286c430ebdaed19c6c09546d233 100644 (file)
@@ -3521,7 +3521,7 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
 
 
 /*
-** This routine sets of a SELECT statement for processing.  The
+** This routine sets up a SELECT statement for processing.  The
 ** following is accomplished:
 **
 **     *  VDBE Cursor numbers are assigned to all FROM-clause terms.
@@ -3553,7 +3553,8 @@ void sqlite3SelectPrep(
 **
 ** The aggregate accumulator is a set of memory cells that hold
 ** intermediate results while calculating an aggregate.  This
-** routine simply stores NULLs in all of those memory cells.
+** routine generates code that stores NULLs in all of those memory
+** cells.
 */
 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
   Vdbe *v = pParse->pVdbe;
index b3cdb2363c6e1f5e0ce54e313c53a1f856d12475..443eaa403560597e05682ced70656c3ebf05f551 100644 (file)
@@ -1690,8 +1690,9 @@ struct Expr {
   i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
   i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
   u8 flags2;             /* Second set of flags.  EP2_... */
-  u8 op2;                /* If a TK_REGISTER, the original value of Expr.op */
-                         /* If TK_COLUMN, the value of p5 for OP_Column */
+  u8 op2;                /* TK_REGISTER: original value of Expr.op
+                         ** TK_COLUMN: the value of p5 for OP_Column
+                         ** TK_AGG_FUNCTION: nesting depth */
   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
   Table *pTab;           /* Table for TK_COLUMN expressions. */
 #if SQLITE_MAX_EXPR_DEPTH>0
@@ -2498,10 +2499,12 @@ struct Walker {
   int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */
   int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
   Parse *pParse;                            /* Parser context.  */
+  int walkerDepth;                          /* Number of subqueries */
   union {                                   /* Extra data for callback */
     NameContext *pNC;                          /* Naming context */
     int i;                                     /* Integer value */
     SrcList *pSrcList;                         /* FROM clause */
+    struct SrcCount *pSrcCount;                /* Counting column references */
   } u;
 };
 
@@ -2835,6 +2838,7 @@ int sqlite3ExprCompare(Expr*, Expr*);
 int sqlite3ExprListCompare(ExprList*, ExprList*);
 void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
 void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
+int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
 Vdbe *sqlite3GetVdbe(Parse*);
 void sqlite3PrngSaveState(void);
 void sqlite3PrngRestoreState(void);
diff --git a/test/aggnested.test b/test/aggnested.test
new file mode 100644 (file)
index 0000000..d763980
--- /dev/null
@@ -0,0 +1,38 @@
+# 2012 August 23
+#
+# 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.
+#
+# This file implements tests for processing aggregate queries with 
+# subqueries in which the subqueries hold the aggregate functions
+# or in which the subqueries are themselves aggregate queries
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_test aggnested-1.1 {
+  db eval {
+    CREATE TABLE t1(a1 INTEGER);
+    INSERT INTO t1 VALUES(1), (2), (3);
+    CREATE TABLE t2(b1 INTEGER);
+    INSERT INTO t2 VALUES(4), (5);
+    SELECT (SELECT group_concat(a1,'x') FROM t2) FROM t1;
+  }
+} {1x2x3}
+do_test aggnested-1.2 {
+  db eval {
+    SELECT
+     (SELECT group_concat(a1,'x') || '-' || group_concat(b1,'y') FROM t2)
+    FROM t1;
+  }
+} {1x2x3-4y5}
+
+finish_test