-C Fix\sANALYZE\sso\sthat\sit\sworks\seven\sif\sthe\sempty_result_callbacks\spragma\sis\nenabled.\sTicket\s#1409.\s(CVS\s2659)
-D 2005-09-06T10:26:47
+C Cleanup\sthe\sprocessing\sof\sMEM_Agg\selements.\s(CVS\s2660)
+D 2005-09-06T20:36:49
F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/delete.c be1fc25c9e109cd8cbab42a43ee696263da7c04b
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
F src/expr.c 8a72157fa6842e84819a8c80521be02ec471180c
-F src/func.c 9da04a6241309a612cf610715944c6a2aaf0f297
+F src/func.c 713cf33a0ab8685d44ed31a9c753983a7ff9fd6e
F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c 484c73bc1309f283a31baa0e114f3ee980536397
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 5650f6fe5ee30e0678985ad7b94da91e3f85752b
F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c
-F src/vdbe.c efde23f8829b5902cfbc8cca3f3fab51a7e9c99a
+F src/vdbe.c 5f0ed87252912fa1d4c989b0c6d7e3d4d2bb337a
F src/vdbe.h 3b29a9af6c7a64ed692bef1fc5f61338f40d2f67
-F src/vdbeInt.h 52811a5182c6f98a10d34a1d1d0188fe3582ae03
-F src/vdbeapi.c f0d36ff0f06bb5315efac5645b62e99db2c175b8
-F src/vdbeaux.c b23bb870ab88fb91a2dd15273922d93314d8a7a3
+F src/vdbeInt.h 7a6b3c1adfa7b23c1f4f15ce0549b5b52a85a635
+F src/vdbeapi.c 46e2fd47e2ce3c1aea9bb48bbbac31a1dc75a6ff
+F src/vdbeaux.c 2cfc66b30be5e293bd72db8084f8cb5c865e8b01
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
-F src/vdbemem.c 4732fd4d1a75dc38549493d7f9a81d02bf7c59b5
+F src/vdbemem.c b6ae3ac842a6759bd8ec4eb1cd428520b5eafc57
F src/where.c 92ab208abe6bec15e81616b8c1a619be23ece506
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 449a7895995013720f5d4c7b3b7f5bd6a5413717
-R 68bd3a3e3907990d3c3125f35717440b
+P bfdaef1224d741deefe211e1e607bac4c80f2d89
+R 93135a9d31c9998d4b9c71aa574ff69f
U drh
-Z 24033ba2c6a1ea752cac6b534c09791f
+Z 6dd7706565f409f6810f70b1066b3664
-bfdaef1224d741deefe211e1e607bac4c80f2d89
\ No newline at end of file
+7ecf3654aa9a275a4cf0c3ec5f63a8c1e0a11fc9
\ No newline at end of file
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.106 2005/08/28 17:00:23 drh Exp $
+** $Id: func.c,v 1.107 2005/09/06 20:36:49 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
}
static void sumFinalize(sqlite3_context *context){
SumCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
+ p = sqlite3_aggregate_context(context, 0);
sqlite3_result_double(context, p ? p->sum : 0.0);
}
static void avgFinalize(sqlite3_context *context){
SumCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
+ p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
sqlite3_result_double(context, p->sum/(double)p->cnt);
}
}
static void countFinalize(sqlite3_context *context){
CountCtx *p;
- p = sqlite3_aggregate_context(context, sizeof(*p));
+ p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int(context, p ? p->n : 0);
}
}
static void minMaxFinalize(sqlite3_context *context){
sqlite3_value *pRes;
- pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem));
- if( pRes->flags ){
- sqlite3_result_value(context, pRes);
+ pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
+ if( pRes ){
+ if( pRes->flags ){
+ sqlite3_result_value(context, pRes);
+ }
+ sqlite3VdbeMemRelease(pRes);
}
- sqlite3VdbeMemRelease(pRes);
}
** 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.480 2005/09/01 12:16:29 drh Exp $
+** $Id: vdbe.c,v 1.481 2005/09/06 20:36:49 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
i = pTos->i;
assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3;
- pMem = &p->pAgg->pCurrent->aMem[i];
- ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
- ctx.pAgg = pMem->z;
- ctx.cnt = ++pMem->i;
+ ctx.pMem = pMem = &p->pAgg->pCurrent->aMem[i];
+ pMem->n++;
ctx.isError = 0;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
ctx.pColl = (CollSeq *)pOp[-1].p3;
}
(ctx.pFunc->xStep)(&ctx, n, apVal);
- pMem->z = ctx.pAgg;
- pMem->flags = MEM_AggCtx;
popStack(&pTos, n+1);
if( ctx.isError ){
rc = SQLITE_ERROR;
pc = pOp->p2 - 1;
}else{
int i;
- sqlite3_context ctx;
Mem *aMem;
if( p->pAgg->pCsr ){
for(i=0; i<p->pAgg->nMem; i++){
FuncDef *pFunc = p->pAgg->apFunc[i];
Mem *pMem = &aMem[i];
- if( pFunc==0 || pFunc->xFinalize==0 ) continue;
- ctx.s.flags = MEM_Null;
- ctx.s.z = pMem->zShort;
- ctx.pAgg = (void*)pMem->z;
- ctx.cnt = pMem->i;
- ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx);
- pMem->z = ctx.pAgg;
- if( pMem->z && pMem->z!=pMem->zShort ){
- sqliteFree( pMem->z );
- }
- *pMem = ctx.s;
- if( pMem->flags & MEM_Short ){
- pMem->z = pMem->zShort;
- }
+ sqlite3VdbeMemFinalize(pMem, pFunc);
}
}
break;
** SQLITE_BLOB.
*/
struct Mem {
- i64 i; /* Integer value */
+ i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
+ double r; /* Real value */
+ char *z; /* String or BLOB value */
int n; /* Number of characters in string value, including '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 type; /* One of MEM_Null, MEM_Str, etc. */
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
- double r; /* Real value */
- char *z; /* String or BLOB value */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char zShort[NBFS]; /* Space for short strings */
};
#define MEM_Static 0x0080 /* Mem.z points to a static string */
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
-
-/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
-** It indicates that the corresponding AggElem.aMem.z points to a
-** aggregate function context that needs to be finalized.
-*/
-#define MEM_AggCtx 0x0400 /* Mem.z points to an agg function context */
+#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
** But this file is the only place where the internal details of this
** structure are known.
**
-** This structure is defined inside of vdbe.c because it uses substructures
+** This structure is defined inside of vdbeInt.h because it uses substructures
** (Mem) which are only defined there.
*/
struct sqlite3_context {
- FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
+ FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
- Mem s; /* The return value is stored here */
- void *pAgg; /* Aggregate context */
- u8 isError; /* Set to true for an error */
- int cnt; /* Number of times that the step function has been called */
- CollSeq *pColl;
+ Mem s; /* The return value is stored here */
+ Mem *pMem; /* Memory cell used to store aggregate context */
+ u8 isError; /* Set to true for an error */
+ CollSeq *pColl; /* Collating sequence */
};
/*
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
+void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeNoPush(u8);
*/
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
- if( p->pAgg==0 ){
+ Mem *pMem = p->pMem;
+ if( (pMem->flags & MEM_Agg)==0 && nByte>0 ){
+ pMem->flags = MEM_Agg;
+ *(FuncDef**)&pMem->i = p->pFunc;
if( nByte<=NBFS ){
- p->pAgg = (void*)p->s.z;
- memset(p->pAgg, 0, nByte);
+ pMem->z = pMem->zShort;
+ memset(pMem->z, 0, nByte);
}else{
- p->pAgg = sqliteMalloc( nByte );
+ pMem->z = sqliteMalloc( nByte );
}
}
- return p->pAgg;
+ return (void*)pMem->z;
}
/*
*/
int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pFunc && p->pFunc->xStep );
- return p->cnt;
+ return p->pMem->n;
}
/*
int i;
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
- if( pAgg->apFunc && 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.isError = 0;
- (*ctx.pFunc->xFinalize)(&ctx);
- pMem->z = ctx.pAgg;
- if( pMem->z!=0 && pMem->z!=pMem->zShort ){
- sqliteFree(pMem->z);
- }
- sqlite3VdbeMemRelease(&ctx.s);
- }else{
- sqlite3VdbeMemRelease(pMem);
+ if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_Agg)!=0 ){
+ sqlite3VdbeMemFinalize(pMem, pAgg->apFunc[i]);
}
+ sqlite3VdbeMemRelease(pMem);
+
}
sqliteFree(pElem);
}
return rc;
}
+/*
+** Memory cell pMem contains the context of an aggregate function.
+** This routine calls the finalize method for that function. The
+** result of the aggregate is stored back into pMem.
+*/
+void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+ 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;
+ }
+ }
+}
+
/*
** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and
** (Mem.type==SQLITE_TEXT).
*/
void sqlite3VdbeMemRelease(Mem *p){
- if( p->flags & MEM_Dyn ){
+ if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){
- p->xDel((void *)p->z);
+ if( p->flags & MEM_Agg ){
+ sqlite3VdbeMemFinalize(p, (FuncDef*)&p->i);
+ assert( (p->flags & MEM_Agg)==0 );
+ sqlite3VdbeMemRelease(p);
+ }else{
+ p->xDel((void *)p->z);
+ }
}else{
sqliteFree(p->z);
}