mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-10 01:02:56 +03:00
Cleanup the processing of MEM_Agg elements. (CVS 2660)
FossilOrigin-Name: 7ecf3654aa9a275a4cf0c3ec5f63a8c1e0a11fc9
This commit is contained in:
22
manifest
22
manifest
@@ -1,5 +1,5 @@
|
||||
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
|
||||
@@ -41,7 +41,7 @@ F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940
|
||||
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
|
||||
@@ -80,13 +80,13 @@ F src/update.c a9d2c5f504212d62da1b094476f1389c0e02f83f
|
||||
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
|
||||
@@ -306,7 +306,7 @@ F www/tclsqlite.tcl 3df553505b6efcad08f91e9b975deb2e6c9bb955
|
||||
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
|
||||
|
@@ -1 +1 @@
|
||||
bfdaef1224d741deefe211e1e607bac4c80f2d89
|
||||
7ecf3654aa9a275a4cf0c3ec5f63a8c1e0a11fc9
|
18
src/func.c
18
src/func.c
@@ -16,7 +16,7 @@
|
||||
** 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>
|
||||
@@ -835,12 +835,12 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -878,7 +878,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -916,11 +916,13 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
27
src/vdbe.c
27
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.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"
|
||||
@@ -4278,10 +4278,8 @@ case OP_AggFunc: { /* no-push */
|
||||
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 ){
|
||||
@@ -4291,8 +4289,6 @@ case OP_AggFunc: { /* no-push */
|
||||
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;
|
||||
@@ -4436,7 +4432,6 @@ case OP_AggNext: { /* no-push */
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
int i;
|
||||
sqlite3_context ctx;
|
||||
Mem *aMem;
|
||||
|
||||
if( p->pAgg->pCsr ){
|
||||
@@ -4448,21 +4443,7 @@ case OP_AggNext: { /* no-push */
|
||||
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;
|
||||
|
@@ -114,13 +114,13 @@ typedef struct Cursor Cursor;
|
||||
** 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 */
|
||||
};
|
||||
@@ -157,12 +157,7 @@ typedef struct Mem Mem;
|
||||
#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
|
||||
@@ -194,17 +189,16 @@ typedef struct VdbeFunc VdbeFunc;
|
||||
** 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -397,6 +391,7 @@ double sqlite3VdbeRealValue(Mem*);
|
||||
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);
|
||||
|
@@ -258,15 +258,18 @@ void *sqlite3_user_data(sqlite3_context *p){
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -325,7 +328,7 @@ void sqlite3_set_auxdata(
|
||||
*/
|
||||
int sqlite3_aggregate_count(sqlite3_context *p){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
return p->cnt;
|
||||
return p->pMem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -776,22 +776,11 @@ static void freeAggElem(AggElem *pElem, Agg *pAgg){
|
||||
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);
|
||||
}
|
||||
|
@@ -187,15 +187,44 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
||||
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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user