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{