aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2002-02-27 19:50:59 +0000
committerdrh <drh@noemail.net>2002-02-27 19:50:59 +0000
commitdd5baa95e81b1aa25d5314c2452afc0560110c08 (patch)
treee2aeb578b67bd2a1b5d1d87191ba4de799807654 /src
parent1350b030c146486e58ab3bc0ca825650eaf0ab97 (diff)
downloadsqlite-dd5baa95e81b1aa25d5314c2452afc0560110c08.tar.gz
sqlite-dd5baa95e81b1aa25d5314c2452afc0560110c08.zip
Try to reduce the number of malloc() for user-defined functions. Begin
transfering built-in functions over to the user-define function mechanism. (CVS 399) FossilOrigin-Name: c4f9e017b449d4036fa8d2bf77b931d4c31d74f7
Diffstat (limited to 'src')
-rw-r--r--src/func.c52
-rw-r--r--src/sqlite.h.in14
-rw-r--r--src/vdbe.c24
3 files changed, 69 insertions, 21 deletions
diff --git a/src/func.c b/src/func.c
index 26c401e12..881b26ab3 100644
--- a/src/func.c
+++ b/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.4 2002/02/27 19:00:22 drh Exp $
+** $Id: func.c,v 1.5 2002/02/27 19:50:59 drh Exp $
*/
#include <ctype.h>
#include <math.h>
@@ -49,13 +49,50 @@ static void lowerFunc(sqlite_func *context, int argc, const char **argv){
/*
** An instance of the following structure holds the context of a
+** sum() or avg() aggregate computation.
+*/
+typedef struct SumCtx SumCtx;
+struct SumCtx {
+ double sum; /* Sum of terms */
+};
+
+/*
+** Routines used to compute the sum or average.
+*/
+static void sumStep(sqlite_func *context, int argc, const char **argv){
+ SumCtx *p;
+ double x;
+ if( argc<1 ) return;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ x = argv[0] ? atof(argv[0]) : 0.0;
+ p->sum += x;
+}
+static void sumFinalize(sqlite_func *context){
+ SumCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p ){
+ sqlite_set_result_double(context, p->sum);
+ }
+}
+static void avgFinalize(sqlite_func *context){
+ SumCtx *p;
+ double rN;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ rN = sqlite_aggregate_count(context);
+ if( p && rN>0.0 ){
+ sqlite_set_result_double(context, p->sum/rN);
+ }
+}
+
+/*
+** An instance of the following structure holds the context of a
** variance or standard deviation computation.
*/
typedef struct StdDevCtx StdDevCtx;
struct StdDevCtx {
double sum; /* Sum of terms */
double sum2; /* Sum of the squares of terms */
- int n; /* Number of terms seen so far */
};
/*
@@ -67,20 +104,21 @@ static void stdDevStep(sqlite_func *context, int argc, const char **argv){
if( argc<1 ) return;
p = sqlite_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
- x = atof(argv[0]);
+ x = argv[0] ? atof(argv[0]) : 0.0;
p->sum += x;
p->sum2 += x*x;
- p->n++;
}
static void stdDevFinalize(sqlite_func *context){
+ double rN = sqlite_aggregate_count(context);
StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
- if( p && p->n>1 ){
- double rN = p->n;
+ if( p && rN>1.0 ){
sqlite_set_result_double(context,
sqrt((p->sum2 - p->sum*p->sum/rN)/(rN-1.0)));
}
}
+
+
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
@@ -90,4 +128,6 @@ void sqliteRegisterBuildinFunctions(sqlite *db){
sqlite_create_function(db, "upper", 1, upperFunc, 0);
sqlite_create_function(db, "lower", 1, lowerFunc, 0);
sqlite_create_aggregate(db, "stddev", 1, stdDevStep, stdDevFinalize, 0);
+ sqlite_create_aggregate(db, "x_sum", 1, sumStep, sumFinalize, 0);
+ sqlite_create_aggregate(db, "x_avg", 1, sumStep, avgFinalize, 0);
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 251bd35d8..b460849fa 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.27 2002/02/27 19:00:22 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.28 2002/02/27 19:50:59 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@@ -391,7 +391,7 @@ int sqlite_create_aggregate(
/*
** The user function implementations call one of the following four routines
** in order to return their results. The first parameter to each of these
-** routines is a copy of the first argument to xFunc() or xFinialize()
+** routines is a copy of the first argument to xFunc() or xFinialize().
** The second parameter to these routines is the result to be returned.
** A NULL can be passed as the second parameter to sqlite_set_result_string()
** in order to return a NULL result.
@@ -419,8 +419,8 @@ void sqlite_set_result_error(sqlite_func*,const char*,int);
void *sqlite_user_data(sqlite_func*);
/*
-** User aggregate functions use the following routine to allocate
-** a structure for storing their context. The first time this routine
+** Aggregate functions use the following routine to allocate
+** a structure for storing their state. The first time this routine
** is called for a particular aggregate, a new structure of size nBytes
** is allocated, zeroed, and returned. On subsequent calls (for the
** same aggregate instance) the same buffer is returned. The implementation
@@ -431,9 +431,9 @@ void *sqlite_user_data(sqlite_func*);
void *sqlite_aggregate_context(sqlite_func*, int nBytes);
/*
-** The next return returns the number of calls to xStep for a particular
-** aggregate function instance. The current call to xStep counts so the
-** function always returns at least 1.
+** The next routine returns the number of calls to xStep for a particular
+** aggregate function instance. The current call to xStep counts so this
+** routine always returns at least 1.
*/
int sqlite_aggregate_count(sqlite_func*);
diff --git a/src/vdbe.c b/src/vdbe.c
index c285eb6f4..0d134ae03 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -30,7 +30,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.124 2002/02/27 19:00:22 drh Exp $
+** $Id: vdbe.c,v 1.125 2002/02/27 19:50:59 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -618,7 +618,11 @@ void *sqlite_user_data(sqlite_func *p){
void *sqlite_aggregate_context(sqlite_func *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
if( p->pAgg==0 ){
- p->pAgg = sqliteMalloc( nByte );
+ if( nByte<=NBFS ){
+ p->pAgg = (void*)p->z;
+ }else{
+ p->pAgg = sqliteMalloc( nByte );
+ }
}
return p->pAgg;
}
@@ -652,18 +656,21 @@ static void AggReset(Agg *pAgg){
AggElem *pElem = sqliteHashData(p);
assert( pAgg->apFunc!=0 );
for(i=0; i<pAgg->nMem; i++){
- if( pAgg->apFunc[i] && (pElem->aMem[i].s.flags & STK_AggCtx)!=0 ){
+ Mem *pMem = &pElem->aMem[i];
+ if( pAgg->apFunc[i] && (pMem->s.flags & STK_AggCtx)!=0 ){
sqlite_func ctx;
ctx.s.flags = STK_Null;
ctx.z = 0;
- ctx.pAgg = pElem->aMem[i].z;
- ctx.cnt = pElem->aMem[i].s.i;
+ ctx.pAgg = pMem->z;
+ ctx.cnt = pMem->s.i;
ctx.isStep = 0;
ctx.isError = 0;
(*pAgg->apFunc[i]->xFinalize)(&ctx);
- }
- if( pElem->aMem[i].s.flags & (STK_Dyn | STK_AggCtx) ){
- sqliteFree(pElem->aMem[i].z);
+ if( pMem->z!=0 && pMem->z!=pMem->s.z ){
+ sqliteFree(pMem->z);
+ }
+ }else if( pMem->s.flags & STK_Dyn ){
+ sqliteFree(pMem->z);
}
}
sqliteFree(pElem);
@@ -4437,6 +4444,7 @@ case OP_AggFunc: {
VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
ctx.pFunc = (UserFunc*)pOp->p3;
pMem = &p->agg.pCurrent->aMem[i];
+ ctx.z = pMem->s.z;
ctx.pAgg = pMem->z;
ctx.cnt = ++pMem->s.i;
ctx.isError = 0;