]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid opening a temp table for aggregate queries with no GROUP BY clause. (CVS 1649)
authordanielk1977 <danielk1977@noemail.net>
Mon, 21 Jun 2004 10:45:06 +0000 (10:45 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Mon, 21 Jun 2004 10:45:06 +0000 (10:45 +0000)
FossilOrigin-Name: 4d02df63496091a1e643601f84313f42130d6282

manifest
manifest.uuid
src/build.c
src/select.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c

index affa485fbb6bb75fbb804a798427cd8eeefd5418..ce103c06a2fcfc5d7660c9816d19a0e983dae805 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sOP_Concat8\sopcode,\ssimilar\sin\sconcept\sto\sOP_String8.\s(CVS\s1648)
-D 2004-06-21T09:06:42
+C Avoid\sopening\sa\stemp\stable\sfor\saggregate\squeries\swith\sno\sGROUP\sBY\sclause.\s(CVS\s1649)
+D 2004-06-21T10:45:07
 F Makefile.in d69d53c543518c1572ee0a8e8723d7e00bdb2266
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -28,7 +28,7 @@ F src/attach.c 05102e2e8ac43ce639d07b47a99c7772a62420e6
 F src/auth.c 60db23b98bb94c8b0178180faaf49dc116674217
 F src/btree.c 0cf8a52a57a7eb13d50719114ee1fa353e89d7d3
 F src/btree.h 32f96abef464cf8765b23ca669acfe90d191fcc5
-F src/build.c b1180cfc82b29fae42f9eac84aa869f3f7e207a8
+F src/build.c ffcd0cd8cd8aac1a45d852c6364c6b5b07cd9dc4
 F src/date.c b3e8b2bef1e3f2ce24e5b057203036defb18c3f1
 F src/delete.c 19287dd204569519636a04eca2b66c49c26e9266
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
@@ -54,7 +54,7 @@ F src/parse.y 097438674976355a10cf177bd97326c548820b86
 F src/pragma.c 0750e1c360647dbe0a991f16133b0fe5e42e5039
 F src/printf.c 823b6a5cbedb6971a9e62f5d83204fe9b0be7c1b
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 7305795965f7702c6d95fc023dee138b40e90d41
+F src/select.c f02a65af34231031896e8442161cb5251e191e75
 F src/shell.c 24b641700c9d90f361fcfa4f432c5b4aff704e6d
 F src/sqlite.h.in a3d593016d1a1a514d7a26c8a353b58caf62e798
 F src/sqliteInt.h b379bc549c9d812090d6c33ff5f229b34346ac0c
@@ -71,11 +71,11 @@ F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a
 F src/utf.c 3a2596013e4b9582d075ca742de7f067ff7dee95
 F src/util.c e31e35d3d76cab7a02045095064897eca49cbce3
 F src/vacuum.c fcb930215a3f6c50087300782555f61ad11dd80c
-F src/vdbe.c 78d675c104d917a3061218775dddc5283cfff49d
+F src/vdbe.c 206ac8aa50978ff2870c3e53dc3564dff5ae8d33
 F src/vdbe.h 2d87155e31e84bb00cdc48cc1ce6987a3a484250
-F src/vdbeInt.h 4d56da610923efa8d4c9db89dff17cb721e69a9b
+F src/vdbeInt.h c0740932621a8d4aac20e0c4235ce44eb5e8dce6
 F src/vdbeapi.c 8a9421341e09b506a934132c9015f26362ae8c0e
-F src/vdbeaux.c 4e0d90a74e315194449e42e097d04028b521887b
+F src/vdbeaux.c b89e05d8a1be4a27ba98c0ae369642c12a2cb44f
 F src/vdbemem.c 9359c53386e070fea9f5403cab0c6f0cfe36496b
 F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
@@ -225,7 +225,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
 F www/version3.tcl af528563442e3039928f9018327a18157e53a44f
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 7a33daef5b49b1f2d89f27e0063372fe4f1702c8
-R 7ca92734bb4802e7f5046704b052bee6
+P bbd3e93348bc3a1178f5278c6cf0b82e75bbf642
+R 721de3571b9dffe04fab1715f24d4561
 U danielk1977
-Z f888e07c9fa8c25fdc20925aefd11399
+Z c3a890995f7791045ca127dcbcc39544
index af75d5edab4bb2075314bd148747ccc745628de0..a5fef3c17c935fac78a0acac5ea85fa368622de7 100644 (file)
@@ -1 +1 @@
-bbd3e93348bc3a1178f5278c6cf0b82e75bbf642
\ No newline at end of file
+4d02df63496091a1e643601f84313f42130d6282
\ No newline at end of file
index 04b60a0a1e704a997810c0ec52b6013c93296b03..8b4309286915cc41086868289a15448e9c90f386 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.228 2004/06/21 09:06:42 danielk1977 Exp $
+** $Id: build.c,v 1.229 2004/06/21 10:45:07 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -959,17 +959,20 @@ CollSeq *sqlite3FindCollSeq(
   return pColl;
 }
 
+/*
+** Invoke the 'collation needed' callback to request a collation sequence
+** in the database text encoding of name zName, length nName.
+** If the collation sequence
+*/
 static void callCollNeeded(sqlite *db, const char *zName, int nName){
-  /* No collation sequence of this type for this encoding is registered.
-  ** Call the collation factory to see if it can supply us with one.
-  */
   char const *zExternal = 0;
   assert( !db->xCollNeeded || !db->xCollNeeded16 );
   if( nName<0 ) nName = strlen(zName);
   if( db->xCollNeeded ){
     zExternal = sqliteStrNDup(zName, nName);
     if( !zExternal ) return;
-      db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
+    db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
+    sqliteFree(zExternal);
   }
   if( db->xCollNeeded16 ){
     sqlite3_value *pTmp = sqlite3GetTransientValue(db);
@@ -980,12 +983,14 @@ static void callCollNeeded(sqlite *db, const char *zName, int nName){
   }
 }
 
+/*
+** This routine is called if the collation factory fails to deliver a
+** collation function in the best encoding but there may be other versions
+** of this collation function (for other text encodings) available. Use one
+** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if
+** possible.
+*/
 static int synthCollSeq(Parse *pParse, CollSeq *pColl){
-  /* The collation factory failed to deliver a function but there may be
-  ** other versions of this collation function (for other text encodings)
-  ** available. Use one of these instead. Avoid a UTF-8 <-> UTF-16
-  ** conversion if possible.
-  */
   CollSeq *pColl2 = 0;
   char *z = pColl->zName;
   int n = strlen(z);
@@ -1040,6 +1045,9 @@ static int synthCollSeq(Parse *pParse, CollSeq *pColl){
 */
 int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
   if( pColl && !pColl->xCmp ){
+    /* No collation sequence of this type for this encoding is registered.
+    ** Call the collation factory to see if it can supply us with one.
+    */
     callCollNeeded(pParse->db, pColl->zName, strlen(pColl->zName));
     if( !pColl->xCmp && synthCollSeq(pParse, pColl) ){
       return SQLITE_ERROR;
index 1811f124918884b9a0116e70ab3f8d29ac2ba1e3..9a7f762d8e5174c0ce35365ecb4b0d91ce3d6c0d 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.194 2004/06/21 07:36:32 danielk1977 Exp $
+** $Id: select.c,v 1.195 2004/06/21 10:45:09 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -2452,17 +2452,14 @@ int sqlite3Select(
   /* Reset the aggregator
   */
   if( isAgg ){
-    int addr = sqlite3VdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
+    int addr = sqlite3VdbeAddOp(v, OP_AggReset, (pGroupBy?0:1), pParse->nAgg);
     for(i=0; i<pParse->nAgg; i++){
       FuncDef *pFunc;
       if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
         sqlite3VdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_FUNCDEF);
       }
     }
-    if( pGroupBy==0 ){
-      sqlite3VdbeAddOp(v, OP_String8, 0, 0);
-      sqlite3VdbeAddOp(v, OP_AggFocus, 0, 0);
-    }else{
+    if( pGroupBy ){
       int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*);
       KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz);
       if( 0==pKey ){
index df1303fcec75eaa7796708b103d8f41549faa8e3..b8cd8507c99147c7fc4f4799cead95aa13faee49 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.383 2004/06/21 09:06:42 danielk1977 Exp $
+** $Id: vdbe.c,v 1.384 2004/06/21 10:45:09 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -170,11 +170,12 @@ static int AggInsert(Agg *p, char *zKey, int nKey){
   memcpy(pElem->zKey, zKey, nKey);
   pElem->nKey = nKey;
 
-  assert( p->pCsr );
-  rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
-  if( rc!=SQLITE_OK ){
-    sqliteFree(pElem);
-    return rc;
+  if( p->pCsr ){
+    rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
+    if( rc!=SQLITE_OK ){
+      sqliteFree(pElem);
+      return rc;
+    }
   }
 
   for(i=0; i<p->nMem; i++){
@@ -4259,19 +4260,29 @@ case OP_MemIncr: {
   break;
 }
 
-/* Opcode: AggReset * P2 P3
+/* Opcode: AggReset P1 P2 P3
 **
 ** Reset the aggregator so that it no longer contains any data.
 ** Future aggregator elements will contain P2 values each and be sorted
 ** using the KeyInfo structure pointed to by P3.
+**
+** If P1 is non-zero, then only a single aggregator row is available (i.e.
+** there is no GROUP BY expression). In this case it is illegal to invoke
+** OP_AggFocus.
 */
 case OP_AggReset: {
   assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
-  rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
+  if( pOp->p1 ){
+    rc = sqlite3VdbeAggReset(0, &p->agg, (KeyInfo *)pOp->p3);
+    p->agg.nMem = pOp->p2;    /* Agg.nMem is used by AggInsert() */
+    AggInsert(&p->agg, 0, 0);
+  }else{
+    rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
+    p->agg.nMem = pOp->p2;
+  }
   if( rc!=SQLITE_OK ){
     goto abort_due_to_error;
   }
-  p->agg.nMem = pOp->p2;
   p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
   if( p->agg.apFunc==0 ) goto no_mem;
   break;
@@ -4368,6 +4379,8 @@ case OP_AggFocus: {
   Stringify(pTos, db->enc);
   zKey = pTos->z;
   nKey = pTos->n;
+  assert( p->agg.pBtree );
+  assert( p->agg.pCsr );
   rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res);
   if( rc!=SQLITE_OK ){
     goto abort_due_to_error;
@@ -4462,11 +4475,19 @@ case OP_AggNext: {
   CHECK_FOR_INTERRUPT;
   if( p->agg.searching==0 ){
     p->agg.searching = 1;
-    rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
-    if( rc!=SQLITE_OK ) goto abort_due_to_error;
+    if( p->agg.pCsr ){
+      rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
+      if( rc!=SQLITE_OK ) goto abort_due_to_error;
+    }else{
+      res = 0;
+    }
   }else{
-    rc = sqlite3BtreeNext(p->agg.pCsr, &res);
-    if( rc!=SQLITE_OK ) goto abort_due_to_error;
+    if( p->agg.pCsr ){
+      rc = sqlite3BtreeNext(p->agg.pCsr, &res);
+      if( rc!=SQLITE_OK ) goto abort_due_to_error;
+    }else{
+      res = 1;
+    }
   }
   if( res!=0 ){
     pc = pOp->p2 - 1;
@@ -4475,10 +4496,10 @@ case OP_AggNext: {
     sqlite3_context ctx;
     Mem *aMem;
 
-    rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
-        (char *)&p->agg.pCurrent);
-    if( rc!=SQLITE_OK ){
-      goto abort_due_to_error;
+    if( p->agg.pCsr ){
+      rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
+          (char *)&p->agg.pCurrent);
+      if( rc!=SQLITE_OK ) goto abort_due_to_error;
     }
     aMem = p->agg.pCurrent->aMem;
     for(i=0; i<p->agg.nMem; i++){
index 5e71fdf7786376cf29f44a5062f8df42b53187b8..f5b3673b641b21e25a8cfbc551ec9a51f06d756f 100644 (file)
@@ -238,11 +238,7 @@ struct Agg {
   int nMem;            /* Number of values stored in each AggElem */
   AggElem *pCurrent;   /* The AggElem currently in focus */
   FuncDef **apFunc;    /* Information about aggregate functions */
-#if 0
-  HashElem *pSearch;   /* The hash element for pCurrent */
-  Hash hash;           /* Hash table of all aggregate elements */
-#endif
-  Btree *pBtree;       /* The temporary btree used to group elements */
+  Btree *pBtree;       /* The tmp. btree used to group elements, if required. */
   BtCursor *pCsr;      /* Read/write cursor to the table in pBtree */
   int nTab;            /* Root page of the table in pBtree */
   u8 searching;        /* True between the first AggNext and AggReset */
index 088f0d2eeb308442d76cfae6b9aadf5b02a424f6..823c0972f1a43f28372521d8c32b4f4b1148853a 100644 (file)
@@ -671,6 +671,35 @@ void sqlite3VdbeSorterReset(Vdbe *p){
   }
 }
 
+/*
+** Free all resources allociated with AggElem pElem, an element of
+** aggregate pAgg.
+*/
+int freeAggElem(AggElem *pElem, Agg *pAgg){
+  int i;
+  for(i=0; i<pAgg->nMem; i++){
+    Mem *pMem = &pElem->aMem[i];
+    if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
+      sqlite3_context ctx;
+      ctx.pFunc = pAgg->apFunc[i];
+      ctx.s.flags = MEM_Null;
+      ctx.pAgg = pMem->z;
+      ctx.cnt = pMem->i;
+      ctx.isStep = 0;
+      ctx.isError = 0;
+      (*pAgg->apFunc[i]->xFinalize)(&ctx);
+      pMem->z = ctx.pAgg;
+      if( pMem->z!=0 && pMem->z!=pMem->zShort ){
+        sqliteFree(pMem->z);
+      }
+      sqlite3VdbeMemRelease(&ctx.s);
+    }else{
+      sqlite3VdbeMemRelease(pMem);
+    }
+  }
+  sqliteFree(pElem);
+}
+
 /*
 ** Reset an Agg structure.  Delete all its contents.
 **
@@ -715,27 +744,7 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
         return rc;
       }
       assert( pAgg->apFunc!=0 );
-      for(i=0; i<pAgg->nMem; i++){
-        Mem *pMem = &pElem->aMem[i];
-        if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
-          sqlite3_context ctx;
-          ctx.pFunc = pAgg->apFunc[i];
-          ctx.s.flags = MEM_Null;
-          ctx.pAgg = pMem->z;
-          ctx.cnt = pMem->i;
-          ctx.isStep = 0;
-          ctx.isError = 0;
-          (*pAgg->apFunc[i]->xFinalize)(&ctx);
-          pMem->z = ctx.pAgg;
-          if( pMem->z!=0 && pMem->z!=pMem->zShort ){
-            sqliteFree(pMem->z);
-          }
-          sqlite3VdbeMemRelease(&ctx.s);
-        }else{
-          sqlite3VdbeMemRelease(pMem);
-        }
-      }
-      sqliteFree(pElem);
+      freeAggElem(pElem, pAgg);
       rc=sqlite3BtreeNext(pCsr, &res);
     }
     if( rc!=SQLITE_OK ){
@@ -744,6 +753,13 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
 
     sqlite3BtreeCloseCursor(pCsr);
     sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
+  }else{ 
+    /* The cursor may not be open because the aggregator was never used,
+    ** or it could be that it was used but there was no GROUP BY clause.
+    */
+    if( pAgg->pCurrent ){
+      freeAggElem(pAgg->pCurrent, pAgg);
+    }
   }
 
   /* If db is not NULL and we have not yet and we have not yet opened
@@ -1313,9 +1329,9 @@ int sqlite3VdbeFinalize(Vdbe *p){
 
 /*
 ** Call the destructor for each auxdata entry in pVdbeFunc for which
-** the corresponding bit in mask is set.  Auxdata entries beyond 31
+** the corresponding bit in mask is clear.  Auxdata entries beyond 31
 ** are always destroyed.  To destroy all auxdata entries, call this
-** routine with mask==-1.
+** routine with mask==0.
 */
 void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
   int i;
@@ -1358,7 +1374,7 @@ void sqlite3VdbeDelete(Vdbe *p){
     }
     if( pOp->p3type==P3_VDBEFUNC ){
       VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
-      sqlite3VdbeDeleteAuxData(pVdbeFunc, -1);
+      sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
       sqliteFree(pVdbeFunc);
     }
 #ifndef NDEBUG