Bug fixes in aggregate processing.  Fewer tests fail. (CVS 2663)

FossilOrigin-Name: c3ac58592f5e6305640868cdf42c129f1a25255d
diff --git a/src/select.c b/src/select.c
index dc1a578..07e1339 100644
--- a/src/select.c
+++ b/src/select.c
@@ -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.261 2005/09/07 21:22:47 drh Exp $
+** $Id: select.c,v 1.262 2005/09/07 22:09:48 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -2431,7 +2431,9 @@
   int i;
   struct AggInfo_func *pF;
   for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
-    sqlite3VdbeAddOp(v, OP_AggFinal, pF->iMem, 0);
+    ExprList *pList = pF->pExpr->pList;
+    sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0,
+                      (void*)pF->pFunc, P3_FUNCDEF);
   }
 }
 
diff --git a/src/vdbe.c b/src/vdbe.c
index c4ad4d5..c9fb9f3 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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.482 2005/09/07 21:22:47 drh Exp $
+** $Id: vdbe.c,v 1.483 2005/09/07 22:09:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4186,16 +4186,24 @@
   break;
 }
 
-/* Opcode: AggFinal P1 * *
+/* Opcode: AggFinal P1 P2 P3
 **
 ** Execute the finalizer function for an aggregate.  P1 is
 ** the memory location that is the accumulator for the aggregate.
+**
+** P2 is the number of arguments that the step function takes and
+** P3 is a pointer to the FuncDef for this function.  The P2
+** argument is not used by this opcode.  It is only there to disambiguate
+** functions that can take varying numbers of arguments.  The
+** P3 argument is only needed for the degenerate case where
+** the step function was not previously called.
 */
 case OP_AggFinal: {        /* no-push */
   Mem *pMem;
   assert( pOp->p1>=0 && pOp->p1<p->nMem );
   pMem = &p->aMem[pOp->p1];
-  sqlite3VdbeMemFinalize(pMem);
+  assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
+  sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
   break;
 }
 
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 77951b2..d2faef8 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -363,7 +363,7 @@
 int sqlite3VdbeMemRealify(Mem*);
 int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
 void sqlite3VdbeMemRelease(Mem *p);
-void sqlite3VdbeMemFinalize(Mem*);
+void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
 #ifndef NDEBUG
 void sqlite3VdbeMemSanity(Mem*, u8);
 int sqlite3VdbeOpcodeNoPush(u8);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 6c786f1..2d94ba0 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -259,14 +259,19 @@
 void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
   assert( p && p->pFunc && p->pFunc->xStep );
   Mem *pMem = p->pMem;
-  if( (pMem->flags & MEM_Agg)==0 && nByte>0 ){
-    pMem->flags = MEM_Agg;
-    *(FuncDef**)&pMem->i = p->pFunc;
-    if( nByte<=NBFS ){
-      pMem->z = pMem->zShort;
-      memset(pMem->z, 0, nByte);
+  if( (pMem->flags & MEM_Agg)==0 ){
+    if( nByte==0 ){
+      assert( pMem->flags==MEM_Null );
+      pMem->z = 0;
     }else{
-      pMem->z = sqliteMalloc( nByte );
+      pMem->flags = MEM_Agg;
+      *(FuncDef**)&pMem->i = p->pFunc;
+      if( nByte<=NBFS ){
+        pMem->z = pMem->zShort;
+        memset(pMem->z, 0, nByte);
+      }else{
+        pMem->z = sqliteMalloc( nByte );
+      }
     }
   }
   return (void*)pMem->z;
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 70a4663..085e2aa 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -192,23 +192,21 @@
 ** This routine calls the finalize method for that function.  The
 ** result of the aggregate is stored back into pMem.
 */
-void sqlite3VdbeMemFinalize(Mem *pMem){
-  if( pMem->flags & MEM_Agg ){
-    FuncDef *pFunc = *(FuncDef**)&pMem->i;
-    if( pFunc && pFunc->xFinalize ){
-      sqlite3_context ctx;
-      ctx.s.flags = MEM_Null;
-      ctx.s.z = pMem->zShort;
-      ctx.pMem = pMem;
-      ctx.pFunc = pFunc;
-      pFunc->xFinalize(&ctx);
-      if( pMem->z && pMem->z!=pMem->zShort ){
-        sqliteFree( pMem->z );
-      }
-      *pMem = ctx.s;
-      if( pMem->flags & MEM_Short ){
-        pMem->z = pMem->zShort;
-      }
+void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+  if( pFunc && pFunc->xFinalize ){
+    sqlite3_context ctx;
+    assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
+    ctx.s.flags = MEM_Null;
+    ctx.s.z = pMem->zShort;
+    ctx.pMem = pMem;
+    ctx.pFunc = pFunc;
+    pFunc->xFinalize(&ctx);
+    if( pMem->z && pMem->z!=pMem->zShort ){
+      sqliteFree( pMem->z );
+    }
+    *pMem = ctx.s;
+    if( pMem->flags & MEM_Short ){
+      pMem->z = pMem->zShort;
     }
   }
 }
@@ -222,7 +220,7 @@
   if( p->flags & (MEM_Dyn|MEM_Agg) ){
     if( p->xDel ){
       if( p->flags & MEM_Agg ){
-        sqlite3VdbeMemFinalize(p);
+        sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
         assert( (p->flags & MEM_Agg)==0 );
         sqlite3VdbeMemRelease(p);
       }else{