]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for correlated subqueries where the parent is an aggregate. Ticket #1105. (CVS...
authordanielk1977 <danielk1977@noemail.net>
Tue, 8 Feb 2005 07:50:40 +0000 (07:50 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 8 Feb 2005 07:50:40 +0000 (07:50 +0000)
FossilOrigin-Name: f0d3ca10c5bccf8fca7143028ebb3e604c0e3f20

manifest
manifest.uuid
src/expr.c
src/select.c
src/sqliteInt.h
src/vdbe.c
test/subquery.test

index 8a1bf2f3ae9fe07d5f3a297a439c38d308e63323..80d06c90ced2de8e75303082417132a56464f993 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\s(highly\sexperimental)\somit_readlock\spragma\sthat\sdisables\sthe\suse\r\nof\sreadlocks\son\sread-only\sdatabases\sthat\sare\sconnected\susing\sATTACH.\s(CVS\s2317)
-D 2005-02-06T02:45:42
+C Fix\sfor\scorrelated\ssubqueries\swhere\sthe\sparent\sis\san\saggregate.\sTicket\s#1105.\s(CVS\s2318)
+D 2005-02-08T07:50:41
 F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -35,7 +35,7 @@ F src/build.c fcb437bcda09a57b3fe898dff5ff558e7536621b
 F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
 F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3
 F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad
-F src/expr.c 1b6b6b16bcb6a6dcc4a5df451d9e652f84b269ae
+F src/expr.c b9ffd249cef8cd0f2d3681da8daf9a4292dcd005
 F src/func.c f096b6771cc0aaa11790aca95773a50a8f74ba73
 F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
@@ -57,10 +57,10 @@ F src/parse.y ee046c1ea30425a817285e52fb1993c2f955e766
 F src/pragma.c 809b95acd9af67297a5f923a1a57d82179e0ad3a
 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 6217e1f72cee7e173b21b252fd42a052f3b4decc
+F src/select.c 37dd84fd228db14e9006e3eafb389f08d823502f
 F src/shell.c 3cb0ef124ed9cd582ce89aec59ff7c659bc6e61b
 F src/sqlite.h.in c85f6bad9ca7de29f505fe886646cfff7df4c55e
-F src/sqliteInt.h 5fa59fd8369ec403bbdf35a9b6fbf7f60bd77cdb
+F src/sqliteInt.h 9a53c5b5c591526e22b89deed38467cb8875b121
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d
 F src/test1.c feac8a742aca920c8ab18a43b3208ae3a834fe9d
@@ -74,7 +74,7 @@ F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be
 F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
 F src/util.c 1b7b9a127b66743ab6cba8d44597aeb570723c99
 F src/vacuum.c 4dbe45a5c41674a04ac45a7586031583386ab119
-F src/vdbe.c 5acf43749f44b0813d47f4b1801538f4aaa7ddbb
+F src/vdbe.c d9ec62c9f63768b4d4f8513b25aded8faf2de17b
 F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd
 F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e
 F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac
@@ -181,7 +181,7 @@ F test/select5.test 2d414f712bff8e590091e08f9b7287600731be00
 F test/select6.test 6e5a1a70a788cdbe515d1252dd0917d7e9d1d71e
 F test/select7.test 8f3362336c10d828ab6fe9c1b8897b484da8b592
 F test/sort.test 312eade533cb3c7667110ccfa6e818db1078fd6c
-F test/subquery.test e607b55276d2536e17e75896cd245ec1c8838f1d
+F test/subquery.test 958bf1752c6b1c5c0b45b243fc74899f2037821e
 F test/subselect.test 3f3f7a940dc3195c3139f4d530385cb54665d614
 F test/table.test a2a58cae70ef2511cbf27d40fb8f570106a2677e
 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
@@ -270,7 +270,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
 F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd
-P 515e5033a5482f55e7edb66d69ff3da7e234ff2e
-R 46e8e0ae6e4ce5a599c5b024b5c2e241
-U drh
-Z dd83c9ab3e3ce7d0c16a2d058d1f0afb
+P 2155448d2128119f74241da0ea07d6713b71765c
+R 606c27806bb193ef40535820164d7cb2
+U danielk1977
+Z ab8a5b2917edd9042037cd2b7cc41ebd
index 909087ae42d45e010272c458d84155f7264a2c35..1a449e39508286050306cad1cf217ada0e3998e1 100644 (file)
@@ -1 +1 @@
-2155448d2128119f74241da0ea07d6713b71765c
\ No newline at end of file
+f0d3ca10c5bccf8fca7143028ebb3e604c0e3f20
\ No newline at end of file
index e282833281ce398e8ecc2c687f9f5a4e06d7e142..487c5395f5f243e99849cdcd717439c2d5ed7a48 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.192 2005/02/05 12:48:48 danielk1977 Exp $
+** $Id: expr.c,v 1.193 2005/02/08 07:50:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -189,6 +189,7 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
   pNew->op = op;
   pNew->pLeft = pLeft;
   pNew->pRight = pRight;
+  pNew->iAgg = -1;
   if( pToken ){
     assert( pToken->dyn==0 );
     pNew->span = pNew->token = *pToken;
@@ -589,26 +590,47 @@ void sqlite3ExprListDelete(ExprList *pList){
 ** The return value from this routine is 1 to abandon the tree walk
 ** and 0 to continue.
 */
+static int walkExprList(ExprList *, int (*)(void *, Expr*), void *);
 static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){
-  ExprList *pList;
   int rc;
   if( pExpr==0 ) return 0;
   rc = (*xFunc)(pArg, pExpr);
   if( rc==0 ){
     if( walkExprTree(pExpr->pLeft, xFunc, pArg) ) return 1;
     if( walkExprTree(pExpr->pRight, xFunc, pArg) ) return 1;
-    pList = pExpr->pList;
-    if( pList ){
-      int i;
-      struct ExprList_item *pItem;
-      for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
-        if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1;
-      }
-    }
+    if( walkExprList(pExpr->pList, xFunc, pArg) ) return 1;
   }
   return rc>1;
 }
 
+/*
+** Call walkExprTree() for every expression in list p.
+*/
+static int walkExprList(ExprList *p, int (*xFunc)(void *, Expr*), void *pArg){
+  int i;
+  struct ExprList_item *pItem;
+  if( !p ) return 0;
+  for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){
+    if( walkExprTree(pItem->pExpr, xFunc, pArg) ) return 1;
+  }
+  return 0;
+}
+
+/*
+** Call walkExprTree() for every expression in Select p, not including
+** expressions that are part of sub-selects in any FROM clause or the LIMIT
+** or OFFSET expressions..
+*/
+static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){
+  walkExprList(p->pEList, xFunc, pArg);
+  walkExprTree(p->pWhere, xFunc, pArg);
+  walkExprList(p->pGroupBy, xFunc, pArg);
+  walkExprTree(p->pHaving, xFunc, pArg);
+  walkExprList(p->pOrderBy, xFunc, pArg);
+  return 0;
+}
+
+
 /*
 ** This routine is designed as an xFunc for walkExprTree().
 **
@@ -1356,8 +1378,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
   op = pExpr->op;
   switch( op ){
     case TK_COLUMN: {
-      if( pParse->useAgg ){
-        sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
+      if( !pParse->fillAgg && pExpr->iAgg>=0 ){
+        sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
       }else if( pExpr->iColumn>=0 ){
         sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
 #ifndef NDEBUG
@@ -1968,49 +1990,64 @@ static int appendAggInfo(Parse *pParse){
 static int analyzeAggregate(void *pArg, Expr *pExpr){
   int i;
   AggExpr *aAgg;
-  Parse *pParse = (Parse*)pArg;
+  NameContext *pNC = (NameContext *)pArg;
+  Parse *pParse = pNC->pParse;
+  SrcList *pSrcList = pNC->pSrcList;
 
   switch( pExpr->op ){
     case TK_COLUMN: {
-      aAgg = pParse->aAgg;
-      for(i=0; i<pParse->nAgg; i++){
-        if( aAgg[i].isAgg ) continue;
-        if( aAgg[i].pExpr->iTable==pExpr->iTable
-         && aAgg[i].pExpr->iColumn==pExpr->iColumn ){
-          break;
+      for(i=0; pSrcList && i<pSrcList->nSrc; i++){
+        if( pExpr->iTable==pSrcList->a[i].iCursor ){
+          aAgg = pParse->aAgg;
+          for(i=0; i<pParse->nAgg; i++){
+            if( aAgg[i].isAgg ) continue;
+            if( aAgg[i].pExpr->iTable==pExpr->iTable
+             && aAgg[i].pExpr->iColumn==pExpr->iColumn ){
+              break;
+            }
+          }
+          if( i>=pParse->nAgg ){
+            i = appendAggInfo(pParse);
+            if( i<0 ) return 1;
+            pParse->aAgg[i].isAgg = 0;
+            pParse->aAgg[i].pExpr = pExpr;
+          }
+          pExpr->iAgg = i;
+          pExpr->iAggCtx = pNC->nDepth;
+          return 1;
         }
       }
-      if( i>=pParse->nAgg ){
-        i = appendAggInfo(pParse);
-        if( i<0 ) return 1;
-        pParse->aAgg[i].isAgg = 0;
-        pParse->aAgg[i].pExpr = pExpr;
-      }
-      pExpr->iAgg = i;
       return 1;
     }
     case TK_AGG_FUNCTION: {
-      aAgg = pParse->aAgg;
-      for(i=0; i<pParse->nAgg; i++){
-        if( !aAgg[i].isAgg ) continue;
-        if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
-          break;
+      if( pNC->nDepth==0 ){
+        aAgg = pParse->aAgg;
+        for(i=0; i<pParse->nAgg; i++){
+          if( !aAgg[i].isAgg ) continue;
+          if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
+            break;
+          }
         }
+        if( i>=pParse->nAgg ){
+          u8 enc = pParse->db->enc;
+          i = appendAggInfo(pParse);
+          if( i<0 ) return 1;
+          pParse->aAgg[i].isAgg = 1;
+          pParse->aAgg[i].pExpr = pExpr;
+          pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
+               pExpr->token.z, pExpr->token.n,
+               pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
+        }
+        pExpr->iAgg = i;
+        return 1;
       }
-      if( i>=pParse->nAgg ){
-        u8 enc = pParse->db->enc;
-        i = appendAggInfo(pParse);
-        if( i<0 ) return 1;
-        pParse->aAgg[i].isAgg = 1;
-        pParse->aAgg[i].pExpr = pExpr;
-        pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
-             pExpr->token.z, pExpr->token.n,
-             pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
-      }
-      pExpr->iAgg = i;
-      return 1;
     }
   }
+  if( pExpr->pSelect ){
+    pNC->nDepth++;
+    walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
+    pNC->nDepth--;
+  }
   return 0;
 }
 
@@ -2025,10 +2062,10 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
 ** If errors are seen, leave an error message in zErrMsg and return
 ** the number of errors.
 */
-int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
-  int nErr = pParse->nErr;
-  walkExprTree(pExpr, analyzeAggregate, pParse);
-  return pParse->nErr - nErr;
+int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
+  int nErr = pNC->pParse->nErr;
+  walkExprTree(pExpr, analyzeAggregate, pNC);
+  return pNC->pParse->nErr - nErr;
 }
 
 /*
index 8bf0f1b95f8bf4bd114b1b891e8cf911d6506138..d9c79df48aa38a39472d1896a9ab082877da1131 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.239 2005/02/05 12:48:48 danielk1977 Exp $
+** $Id: select.c,v 1.240 2005/02/08 07:50:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1241,6 +1241,7 @@ static int matchOrderbyToColumn(
       pE->op = TK_COLUMN;
       pE->iColumn = iCol;
       pE->iTable = iTable;
+      pE->iAgg = -1;
       pOrderBy->a[i].done = 1;
     }
     if( iCol<0 && mustComplete ){
@@ -2095,6 +2096,9 @@ static int flattenSubquery(
   */
   p->isDistinct = p->isDistinct || pSub->isDistinct;
 
+  /*
+  ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
+  */
   if( pSub->pLimit ){
     p->pLimit = pSub->pLimit;
     pSub->pLimit = 0;
@@ -2412,7 +2416,6 @@ int sqlite3SelectResolve(
 ** saveAggregateInfo() and restoreAggregateInfo().
 */ 
 struct AggregateInfo {
-  u8 useAgg;
   int nAgg;
   AggExpr *aAgg;
 };
@@ -2426,10 +2429,8 @@ typedef struct AggregateInfo AggregateInfo;
 static void saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
   pInfo->aAgg = pParse->aAgg;
   pInfo->nAgg = pParse->nAgg;
-  pInfo->useAgg = pParse->useAgg;
   pParse->aAgg = 0;
   pParse->nAgg = 0;
-  pParse->useAgg = 0;
 }
 
 /*
@@ -2441,7 +2442,6 @@ static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
   sqliteFree(pParse->aAgg);
   pParse->aAgg = pInfo->aAgg;
   pParse->nAgg = pInfo->nAgg;
-  pParse->useAgg = pInfo->useAgg;
 }
   
 /*
@@ -2674,26 +2674,31 @@ int sqlite3Select(
   /* Do an analysis of aggregate expressions.
   */
   if( isAgg || pGroupBy ){
+    NameContext sNC;
+    memset(&sNC, 0, sizeof(sNC));
+    sNC.pParse = pParse;
+    sNC.pSrcList = pTabList;
+
     assert( pParse->nAgg==0 );
     isAgg = 1;
     for(i=0; i<pEList->nExpr; i++){
-      if( sqlite3ExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){
+      if( sqlite3ExprAnalyzeAggregates(&sNC, pEList->a[i].pExpr) ){
         goto select_end;
       }
     }
     if( pGroupBy ){
       for(i=0; i<pGroupBy->nExpr; i++){
-        if( sqlite3ExprAnalyzeAggregates(pParse, pGroupBy->a[i].pExpr) ){
+        if( sqlite3ExprAnalyzeAggregates(&sNC, pGroupBy->a[i].pExpr) ){
           goto select_end;
         }
       }
     }
-    if( pHaving && sqlite3ExprAnalyzeAggregates(pParse, pHaving) ){
+    if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
       goto select_end;
     }
     if( pOrderBy ){
       for(i=0; i<pOrderBy->nExpr; i++){
-        if( sqlite3ExprAnalyzeAggregates(pParse, pOrderBy->a[i].pExpr) ){
+        if( sqlite3ExprAnalyzeAggregates(&sNC, pOrderBy->a[i].pExpr) ){
           goto select_end;
         }
       }
@@ -2765,8 +2770,9 @@ int sqlite3Select(
   */
   else{
     AggExpr *pAgg;
+    int lbl1 = 0;
+    pParse->fillAgg = 1;
     if( pGroupBy ){
-      int lbl1;
       for(i=0; i<pGroupBy->nExpr; i++){
         sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr);
       }
@@ -2775,11 +2781,14 @@ int sqlite3Select(
       sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0);
       lbl1 = sqlite3VdbeMakeLabel(v);
       sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1);
-      for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
-        if( pAgg->isAgg ) continue;
-        sqlite3ExprCode(pParse, pAgg->pExpr);
-        sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
-      }
+    }
+    for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
+      if( pAgg->isAgg ) continue;
+      sqlite3ExprCode(pParse, pAgg->pExpr);
+      sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
+    }
+    pParse->fillAgg = 0;
+    if( lbl1<0 ){
       sqlite3VdbeResolveLabel(v, lbl1);
     }
     for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
@@ -2819,7 +2828,6 @@ int sqlite3Select(
     int endagg = sqlite3VdbeMakeLabel(v);
     int startagg;
     startagg = sqlite3VdbeAddOp(v, OP_AggNext, 0, endagg);
-    pParse->useAgg = 1;
     if( pHaving ){
       sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
     }
@@ -2830,7 +2838,6 @@ int sqlite3Select(
     sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
     sqlite3VdbeResolveLabel(v, endagg);
     sqlite3VdbeAddOp(v, OP_Noop, 0, 0);
-    pParse->useAgg = 0;
   }
 
   /* If there is an ORDER BY clause, then we need to sort the results
index 627aeae65d9b2a71a9efa49f4323d3121fd1146b..786a16e4b5b847827fd3ecfee9d2fb2c11ddd269 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.368 2005/02/06 02:45:43 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.369 2005/02/08 07:50:42 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -812,8 +812,9 @@ struct Expr {
   Token span;            /* Complete text of the expression */
   int iTable, iColumn;   /* When op==TK_COLUMN, then this expr node means the
                          ** iColumn-th field of the iTable-th table. */
-  int iAgg;              /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
+  int iAgg;              /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
                          ** result from the iAgg-th element of the aggregator */
+  int iAggCtx;           /* The value to pass as P1 of OP_AggGet. */
   Select *pSelect;       /* When the expression is a sub-select.  Also the
                          ** right side of "<expr> IN (<select>)" */
 };
@@ -1091,8 +1092,7 @@ struct Parse {
   int cookieValue[MAX_ATTACHED+2];  /* Values of cookies to verify */
   int cookieGoto;      /* Address of OP_Goto to cookie verifier subroutine */
   u32 writeMask;       /* Start a write transaction on these databases */
-  u8 useAgg;           /* If true, extract field values from the aggregator
-                       ** while generating expressions.  Normally false */
+  u8 fillAgg;          /* If true, ignore the Expr.iAgg field. Normally false */
 
   /* Above is constant between recursions.  Below is reset before and after
   ** each recursion */
@@ -1410,7 +1410,7 @@ int sqlite3ExprCheck(Parse*, Expr*, int, int*);
 int sqlite3ExprCompare(Expr*, Expr*);
 int sqliteFuncId(Token*);
 int sqlite3ExprResolveNames(NameContext *, Expr *);
-int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
+int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
 Vdbe *sqlite3GetVdbe(Parse*);
 void sqlite3Randomness(int, void*);
 void sqlite3RollbackAll(sqlite3*);
index d27a8bf51b5d83b63092c21d82030415ca2a64b6..98d5c0d58e60006c075a0702d02bbbd7ecfa1777 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.453 2005/02/05 12:48:48 danielk1977 Exp $
+** $Id: vdbe.c,v 1.454 2005/02/08 07:50:42 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4395,31 +4395,39 @@ case OP_AggSet: {
   break;
 }
 
-/* Opcode: AggGet * P2 *
+/* Opcode: AggGet P1 P2 *
 **
 ** Push a new entry onto the stack which is a copy of the P2-th field
 ** of the current aggregate.  Strings are not duplicated so
 ** string values will be ephemeral.
+**
+** If P1 is zero, then the value is pulled out of the current aggregate
+** in the current aggregate context. If P1 is greater than zero, then
+** the value is taken from the P1th outer aggregate context. (i.e. if
+** P1==1 then read from the aggregate context that will be restored
+** by the next OP_AggContextPop opcode).
 */
 case OP_AggGet: {
   AggElem *pFocus;
   int i = pOp->p2;
-  pFocus = p->pAgg->pCurrent;
+  Agg *pAgg = &p->pAgg[-pOp->p1];
+  assert( pAgg>=p->apAgg );
+  pFocus = pAgg->pCurrent;
   if( pFocus==0 ){
     int res;
     if( sqlite3_malloc_failed ) goto no_mem;
-    rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
+    rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
     if( rc!=SQLITE_OK ){
       return rc;
     }
     if( res!=0 ){
-      rc = AggInsert(p->pAgg, "", 1);
-      pFocus = p->pAgg->pCurrent;
+      rc = AggInsert(pAgg, "", 1);
+      pFocus = pAgg->pCurrent;
     }else{
-      rc = sqlite3BtreeData(p->pAgg->pCsr, 0, 4, (char *)&pFocus);
+      rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
     }
   }
-  assert( i>=0 && i<p->pAgg->nMem );
+  assert( i>=0 && i<pAgg->nMem );
   pTos++;
   sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
   if( pTos->flags&MEM_Str ){
index c76c08e2d2b0070cd279382d348891fc65563c6f..b92cb57910f3d8f8123d3b3d5727200e4ae23fe6 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is testing correlated subqueries
 #
-# $Id: subquery.test,v 1.4 2005/01/30 11:11:44 danielk1977 Exp $
+# $Id: subquery.test,v 1.5 2005/02/08 07:50:42 danielk1977 Exp $
 #
 
 set testdir [file dirname $argv0]
@@ -216,6 +216,36 @@ do_test subquery-3.2 {
   }
 } {1}
 
+# Test Cases subquery-3.3.* test correlated subqueries where the
+# parent query is an aggregate query. Ticket #1105 is an example
+# of such a query.
+#
+do_test subquery-3.3.1 {
+  execsql {
+    SELECT a, (SELECT b) FROM t1 GROUP BY a;
+  }
+} {1 2}
+do_test subquery-3.3.2 {
+  catchsql {DROP TABLE t2}
+  execsql {
+    CREATE TABLE t2(c, d);
+    INSERT INTO t2 VALUES(1, 'one');
+    INSERT INTO t2 VALUES(2, 'two');
+    SELECT a, (SELECT d FROM t2 WHERE a=c) FROM t1 GROUP BY a;
+  }
+} {1 one}
+do_test subquery-3.3.3 {
+  execsql {
+    INSERT INTO t1 VALUES(2, 4);
+    SELECT max(a), (SELECT d FROM t2 WHERE a=c) FROM t1;
+  }
+} {2 two}
+do_test subquery-3.3.3 {
+  execsql {
+    SELECT a, (SELECT (SELECT d FROM t2 WHERE a=c)) FROM t1 GROUP BY a;
+  }
+} {1 one 2 two}
+
 #------------------------------------------------------------------
 # These tests - subquery-4.* - use the TCL statement cache to try 
 # and expose bugs to do with re-using statements that have been