Revise the API for user-defined functions. (CVS 398)

FossilOrigin-Name: 633951f0fa11c91f93aa2862df84691750c01e73
This commit is contained in:
drh 2002-02-27 19:00:20 +00:00
parent 4e0f995347
commit 1350b030c1
10 changed files with 331 additions and 146 deletions

View File

@ -1,5 +1,5 @@
C The\suser-defined\sfunction\sroutines\sfailed\sto\sdetect\sa\smalloc()\sfailure.\s(CVS\s397)
D 2002-02-27T01:53:13
C Revise\sthe\sAPI\sfor\suser-defined\sfunctions.\s(CVS\s398)
D 2002-02-27T19:00:21
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@ -23,12 +23,12 @@ F src/btree.c 495275fe14f3b718cf2f691dce979d4c0e1f8e5d
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 7ada2426caba70cb1072ba268bedb694b5018065
F src/delete.c 950d8f9097361419f1963875f9943344b469cf02
F src/expr.c 92ff4a2d87f7443f6081ba2d51e25c27e10c7b4e
F src/func.c bed0099aaa558f8bfc50d9349bf7da2c99903f47
F src/expr.c ea2209a6bdefea23db988b470fc16dbf9d5b3a5a
F src/func.c f020b8c659c95ba1e46cab548ada582ebf8c6c3c
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
F src/insert.c 164d2d5e943268a8ff0594e1947599e04df0ce11
F src/main.c cbfa66d53578935790488f37f476d4932e36c01a
F src/main.c 98f6c6f288e8c9e986634504d9882f348a56edb6
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
@ -37,11 +37,11 @@ F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
F src/parse.y fc460cda6f475beae963c7f9c737cf13f44f3420
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c c74b6349d5630e05aceef73aaa8ed5e09a793fc4
F src/select.c a8e90e8f8366b72830010dd6a9bfbf121d2e9370
F src/shell.c 9f8249ca5b8f8aad40becd778c151b58c0d6109e
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in f1421919a4437a377fb712b98835a224482e776e
F src/sqliteInt.h 4076aef24feec5ad98a9aa98200af29428ef94ba
F src/sqlite.h.in 681dd71442788f900439b624ad1ea2b98f178904
F src/sqliteInt.h 4e746aa13c5fa39a31a89b73afcd33fa164e8b4f
F src/table.c 203a09d5d0009eeeb1f670370d52b4ce163a3b52
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
@ -51,8 +51,8 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 4b5d30590a744b9bb5605a92d1f620ab2e7e75af
F src/update.c 18971d265b0341574b7e3f73116e7947ddab0997
F src/util.c 40a12067fa7b18c7e0461b3256b1353c755b59ac
F src/vdbe.c b2c51a114cff35b9ccb7bbfe57483dabf77ed63f
F src/vdbe.h 98e445d624fb7d3442b5c06058dcb01182397d12
F src/vdbe.c 1a5378625687ced2acaa01e200cb63f07f780ad6
F src/vdbe.h 785b2f175f8be2af285d137125f30042ce8a53b5
F src/where.c 664be01b0ce9ffaecbde609afbd4d8d3e5ed1585
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@ -127,7 +127,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 668ef6380eba256ef82477b63aef850249a619a0
R 672b44d109bf7bbf0ab39b1722058efe
P 085b0d671a1dac964693d69d866224de155dfe4c
R 06586960572c0c651395cc4d56fdf6f3
U drh
Z f74017b4041ef28aa366f6915101de05
Z 67f54dfeaa3612775fa7c5da9d11c294

View File

@ -1 +1 @@
085b0d671a1dac964693d69d866224de155dfe4c
633951f0fa11c91f93aa2862df84691750c01e73

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.47 2002/02/27 01:53:13 drh Exp $
** $Id: expr.c,v 1.48 2002/02/27 19:00:21 drh Exp $
*/
#include "sqliteInt.h"
@ -1003,7 +1003,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteExprCode(pParse, pList->a[i].pExpr);
}
sqliteVdbeAddOp(v, OP_UserFunc, pList->nExpr, 0);
sqliteVdbeChangeP3(v, -1, (char*)pUser->xFunc, P3_POINTER);
sqliteVdbeChangeP3(v, -1, (char*)pUser, P3_POINTER);
break;
}
default: {
@ -1396,8 +1396,7 @@ UserFunc *sqliteFindUserFunction(
){
UserFunc *pFirst, *p, *pMaybe;
pFirst = p = (UserFunc*)sqliteHashFind(&db->userFunc, zName, nName);
if( p==0 ) return 0;
if( !createFlag && nArg<0 ){
if( p && !createFlag && nArg<0 ){
while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
return p;
}

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.3 2002/02/26 23:55:31 drh Exp $
** $Id: func.c,v 1.4 2002/02/27 19:00:22 drh Exp $
*/
#include <ctype.h>
#include <math.h>
@ -26,7 +26,7 @@
/*
** Implementation of the upper() and lower() SQL functions.
*/
static void upperFunc(void *context, int argc, const char **argv){
static void upperFunc(sqlite_func *context, int argc, const char **argv){
char *z;
int i;
if( argc<1 || argv[0]==0 ) return;
@ -36,7 +36,7 @@ static void upperFunc(void *context, int argc, const char **argv){
if( islower(z[i]) ) z[i] = toupper(z[i]);
}
}
static void lowerFunc(void *context, int argc, const char **argv){
static void lowerFunc(sqlite_func *context, int argc, const char **argv){
char *z;
int i;
if( argc<1 || argv[0]==0 ) return;
@ -61,32 +61,24 @@ struct StdDevCtx {
/*
** Routines used to compute the standard deviation as an aggregate.
*/
static void *stdDevStep(void *stddev, int argc, char **argv){
static void stdDevStep(sqlite_func *context, int argc, const char **argv){
StdDevCtx *p;
double x;
if( argc<1 ) return 0;
if( stddev==0 ){
p = malloc( sizeof(*p) );
p->n = 0;
p->sum = 0.0;
p->sum2 = 0.0;
}else{
p = (StdDevCtx*)stddev;
}
if( argc<1 ) return;
p = sqlite_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
x = atof(argv[0]);
p->sum += x;
p->sum2 += x*x;
p->n++;
return p;
}
static void stdDevFinalize(void *stddev, void *context){
StdDevCtx *p = (StdDevCtx*)stddev;
if( context && p && p->n>1 ){
static void stdDevFinalize(sqlite_func *context){
StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
if( p && p->n>1 ){
double rN = p->n;
sqlite_set_result_double(context,
sqrt((p->sum2 - p->sum*p->sum/rN)/(rN-1.0)));
}
if( stddev ) free(stddev);
}
/*
@ -95,7 +87,7 @@ static void stdDevFinalize(void *stddev, void *context){
** external linkage.
*/
void sqliteRegisterBuildinFunctions(sqlite *db){
sqlite_create_function(db, "upper", 1, upperFunc);
sqlite_create_function(db, "lower", 1, lowerFunc);
sqlite_create_aggregate(db, "stddev", 1, stdDevStep, stdDevFinalize);
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);
}

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.64 2002/02/27 01:53:13 drh Exp $
** $Id: main.c,v 1.65 2002/02/27 19:00:22 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -643,7 +643,8 @@ int sqlite_create_function(
sqlite *db, /* Add the function to this database connection */
const char *zName, /* Name of the function to add */
int nArg, /* Number of arguments */
void (*xFunc)(void*,int,const char**) /* Implementation of the function */
void (*xFunc)(sqlite_func*,int,const char**), /* The implementation */
void *pUserData /* User data */
){
UserFunc *p;
if( db==0 || zName==0 ) return 1;
@ -652,14 +653,16 @@ int sqlite_create_function(
p->xFunc = xFunc;
p->xStep = 0;
p->xFinalize = 0;
p->pUserData = pUserData;
return 0;
}
int sqlite_create_aggregate(
sqlite *db, /* Add the function to this database connection */
const char *zName, /* Name of the function to add */
int nArg, /* Number of arguments */
void *(*xStep)(void*,int,const char**), /* The step function */
void (*xFinalize)(void*,void*) /* The finalizer */
void (*xStep)(sqlite_func*,int,const char**), /* The step function */
void (*xFinalize)(sqlite_func*), /* The finalizer */
void *pUserData /* User data */
){
UserFunc *p;
if( db==0 || zName==0 ) return 1;
@ -668,5 +671,6 @@ int sqlite_create_aggregate(
p->xFunc = 0;
p->xStep = xStep;
p->xFinalize = xFinalize;
p->pUserData = pUserData;
return 0;
}

View File

@ -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.67 2002/02/27 01:47:12 drh Exp $
** $Id: select.c,v 1.68 2002/02/27 19:00:22 drh Exp $
*/
#include "sqliteInt.h"
@ -747,6 +747,64 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
return 0;
}
/*
** This routine attempts to flatten subqueries in order to speed
** execution. It returns 1 if it makes changes and 0 if no flattening
** occurs.
**
** To understand the concept of flattening, consider the following
** query:
**
** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
**
** The default way of implementing this query is to execute the
** subquery first and store the results in a temporary table, then
** run the outer query on that temporary table. This requires two
** passes over the data. Furthermore, because the temporary table
** has no indices, the WHERE clause on the outer query cannot be
** optimized using indices.
**
** This routine attempts to write queries such as the above into
** a single flat select, like this:
**
** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
**
** The code generated for this simpification gives the same result
** but only has to scan the data once.
**
** Generally speaking, flattening is only possible if the subquery
** query is a simple query without a GROUP BY clause or the DISTINCT
** keyword and the outer query is not a join.
**
** If flattening is not possible, this routine is a no-op and return 0.
** If flattening is possible, this routine rewrites the query into
** the simplified form and return 1.
**
** All of the expression analysis must occur before this routine runs.
** This routine depends on the results of the expression analysis.
*/
int flattenSubqueries(Select *p){
Select *pSub;
if( p->pSrc->nId>1 ){
return 0; /* Cannot optimize: The outer query is a join. */
}
pSub = p->pSrc->a[0].pSelect;
if( pSub==0 ){
return 0; /* Nothing to optimize: There is no subquery. */
}
if( pSub->isDistinct ){
return 0; /* Subquery contains DISTINCT keyword */
}
if( pSub->pGroupBy ){
return 0; /* Subquery contains a GROUP BY clause */
}
if( pSub->pPrior ){
return 0; /* Subquery is the union of two or more queries */
}
return 0;
}
/*
** Analyze the SELECT statement passed in as an argument to see if it
** is a simple min() or max() query. If it is and this query can be
@ -1056,6 +1114,14 @@ int sqliteSelect(
}
}
/* Try to merge subqueries in the FROM clause into the main
** query.
*/
if( flattenSubqueries(p) ){
pEList = p->pEList;
pWhere = p->pWhere;
}
/* Check for the special case of a min() or max() function by itself
** in the result set.
*/
@ -1134,8 +1200,8 @@ int sqliteSelect(
for(i=0; i<pParse->nAgg; i++){
UserFunc *pUser;
if( (pUser = pParse->aAgg[i].pUser)!=0 && pUser->xFinalize!=0 ){
sqliteVdbeAddOp(v, OP_AggFinalizer, 0, i);
sqliteVdbeChangeP3(v, -1, (char*)pUser->xFinalize, P3_POINTER);
sqliteVdbeAddOp(v, OP_AggInit, 0, i);
sqliteVdbeChangeP3(v, -1, (char*)pUser, P3_POINTER);
}
}
if( pGroupBy==0 ){
@ -1214,7 +1280,6 @@ int sqliteSelect(
for(j=0; j<pE->pList->nExpr; j++){
sqliteExprCode(pParse, pE->pList->a[j].pExpr);
}
sqliteVdbeAddOp(v, OP_AggGet, 0, i);
switch( pE->iColumn ){
case FN_Min: op = OP_Min; break;
case FN_Max: op = OP_Max; break;
@ -1223,14 +1288,16 @@ int sqliteSelect(
case FN_Unknown: op = OP_AggFunc; break;
}
if( op!=OP_AggFunc ){
sqliteVdbeAddOp(v, OP_AggGet, 0, i);
sqliteVdbeAddOp(v, op, 0, 0);
sqliteVdbeAddOp(v, OP_AggSet, 0, i);
}else{
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList->nExpr);
assert( pParse->aAgg[i].pUser!=0 );
assert( pParse->aAgg[i].pUser->xStep!=0 );
sqliteVdbeChangeP3(v,-1,(char*)pParse->aAgg[i].pUser->xStep,P3_POINTER);
sqliteVdbeChangeP3(v, -1, (char*)pParse->aAgg[i].pUser, P3_POINTER);
}
sqliteVdbeAddOp(v, OP_AggSet, 0, i);
}
}

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.26 2002/02/23 23:45:45 drh Exp $
** @(#) $Id: sqlite.h.in,v 1.27 2002/02/27 19:00:22 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@ -362,40 +362,80 @@ int sqlite_get_table_vprintf(
va_list ap /* Arguments to the format string */
);
/*
** A pointer to the following structure is used to communicate with
** the implementations of user-defined functions.
*/
typedef struct sqlite_func sqlite_func;
/*
** Use the following routines to create new user-defined functions. See
** the documentation for details.
*/
int sqlite_create_function(
sqlite*, /* Database where the new function is registered */
const char *zName, /* Name of the new function */
int nArg, /* Number of arguments. -1 means any number */
void (*xFunc)(void*,int,const char**) /* C code to implement the function */
sqlite*, /* Database where the new function is registered */
const char *zName, /* Name of the new function */
int nArg, /* Number of arguments. -1 means any number */
void (*xFunc)(sqlite_func*,int,const char**), /* C code to implement */
void *pUserData /* Available via the sqlite_user_data() call */
);
int sqlite_create_aggregate(
sqlite*, /* Database where the new function is registered */
const char *zName, /* Name of the function */
int nArg, /* Number of arguments */
void *(*xStep)(void*,int,const char**), /* Called for each row */
void (*xFinalize)(void*,void*) /* Called once to get final result */
sqlite*, /* Database where the new function is registered */
const char *zName, /* Name of the function */
int nArg, /* Number of arguments */
void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */
void (*xFinalize)(sqlite_func*), /* Called once to get final result */
void *pUserData /* Available via the sqlite_user_data() call */
);
/*
** 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 the second argument
** to xFinalize(). 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.
** 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.
**
** The 3rd argument to _string and _error is the number of characters to
** take from the string. If this argument is negative, then all characters
** up to and including the first '\000' are used.
**
** The sqlite_set_result_string() function allocates a buffer to hold the
** result and returns a pointer to this buffer. The calling routine
** (that is, the implmentation of a user function) can alter the content
** of this buffer if desired.
*/
char *sqlite_set_result_string(void*,const char*,int);
void sqlite_set_result_int(void*,int);
void sqlite_set_result_double(void*,double);
void sqlite_set_result_error(void*,const char*,int);
char *sqlite_set_result_string(sqlite_func*,const char*,int);
void sqlite_set_result_int(sqlite_func*,int);
void sqlite_set_result_double(sqlite_func*,double);
void sqlite_set_result_error(sqlite_func*,const char*,int);
/*
** The pUserData parameter to the sqlite_create_function() and
** sqlite_create_aggregate() routines used to register user functions
** is available to the implementation of the function using this
** call.
*/
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
** 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
** of the aggregate can use the returned buffer to accumulate data.
**
** The buffer allocated is freed automatically be SQLite.
*/
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.
*/
int sqlite_aggregate_count(sqlite_func*);
#ifdef __cplusplus
} /* End of the 'extern "C"' block */

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.94 2002/02/27 01:47:12 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.95 2002/02/27 19:00:22 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@ -206,11 +206,12 @@ struct sqlite {
** points to a linked list of these structures.
*/
struct UserFunc {
void (*xFunc)(void*,int,const char**); /* Regular function */
void *(*xStep)(void*,int,const char**); /* Aggregate function step */
void (*xFinalize)(void*,void*); /* Aggregate function finializer */
int nArg; /* Number of arguments */
UserFunc *pNext; /* Next function with same name */
void (*xFunc)(sqlite_func*,int,const char**); /* Regular function */
void *(*xStep)(sqlite_func*,int,const char**); /* Aggregate function step */
void (*xFinalize)(sqlite_func*); /* Aggregate function finializer */
int nArg; /* Number of arguments */
void *pUserData; /* User data parameter */
UserFunc *pNext; /* Next function with same name */
};
/*

View File

@ -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.123 2002/02/24 03:25:16 drh Exp $
** $Id: vdbe.c,v 1.124 2002/02/27 19:00:22 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -142,17 +142,30 @@ typedef struct Mem Mem;
** It indicates that the corresponding AggElem.aMem.z points to a
** user-defined aggregate context that needs to be finalized.
*/
#define STK_AggCtx 0x0040 /* zStack[] points to an user function context */
#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */
/*
** The "context" argument for a user-defined function.
** The "context" argument for a user-defined function. A pointer to an
** instance of this structure is the first argument to the routines used
** implement user-defined SQL functions.
**
** There is a typedef for this structure in sqlite.h. So all routines,
** even the public interface to SQLite, can use a pointer to this structure.
** 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
** (Stack) which are only defined there.
*/
struct UserFuncContext {
Stack s; /* Small string, integer, and floating point values go here */
char *z; /* Space for holding dynamic string results */
int isError; /* Set to true for an error */
struct sqlite_func {
UserFunc *pFunc; /* Pointer to function information. MUST BE FIRST */
Stack s; /* Small strings, ints, and double values go here */
char *z; /* Space for holding dynamic string results */
void *pAgg; /* Aggregate context */
u8 isError; /* Set to true for an error */
u8 isStep; /* Current in the step function */
int cnt; /* Number of times that the step function has been called */
};
typedef struct UserFuncContext UserFuncContext;
/*
** An Agg structure describes an Aggregator. Each Agg consists of
@ -168,7 +181,7 @@ struct Agg {
AggElem *pCurrent; /* The AggElem currently in focus */
HashElem *pSearch; /* The hash element for pCurrent */
Hash hash; /* Hash table of all aggregate elements */
void (**axFinalize)(void*,void*); /* Array of nMem finalizers */
UserFunc **apFunc; /* Information about user-defined aggregate functions */
};
struct AggElem {
char *zKey; /* The key to this AggElem */
@ -525,9 +538,13 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
**
** The sqlite_set_result_int() and sqlite_set_result_double() set the return
** value of the user function to an integer or a double.
**
** These routines are defined here in vdbe.c because they depend on knowing
** the internals of the sqlite_func structure which is only defined in that
** one source file.
*/
char *sqlite_set_result_string(void *context, const char *zResult, int n){
UserFuncContext *p = (UserFuncContext*)context;
char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
}
@ -554,49 +571,106 @@ char *sqlite_set_result_string(void *context, const char *zResult, int n){
p->s.n = n;
return p->z;
}
void sqlite_set_result_int(void *context, int iResult){
UserFuncContext *p = (UserFuncContext*)context;
void sqlite_set_result_int(sqlite_func *p, int iResult){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
}
p->s.i = iResult;
p->s.flags = STK_Int;
}
void sqlite_set_result_double(void *context, double rResult){
UserFuncContext *p = (UserFuncContext*)context;
void sqlite_set_result_double(sqlite_func *p, double rResult){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
}
p->s.r = rResult;
p->s.flags = STK_Real;
}
void sqlite_set_result_error(void *context, const char *zMsg, int n){
UserFuncContext *p = (UserFuncContext*)context;
sqlite_set_result_string(context, zMsg, n);
void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){
assert( !p->isStep );
sqlite_set_result_string(p, zMsg, n);
p->isError = 1;
}
/*
** Reset an Agg structure. Delete all its contents.
** Extract the user data from a sqlite_func structure and return a
** pointer to it.
**
** This routine is defined here in vdbe.c because it depends on knowing
** the internals of the sqlite_func structure which is only defined in that
** one source file.
*/
void *sqlite_user_data(sqlite_func *p){
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
/*
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
**
** This routine is defined here in vdbe.c because it depends on knowing
** the internals of the sqlite_func structure which is only defined in that
** one source file.
*/
void *sqlite_aggregate_context(sqlite_func *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
if( p->pAgg==0 ){
p->pAgg = sqliteMalloc( nByte );
}
return p->pAgg;
}
/*
** Return the number of times the Step function of a user-defined
** aggregate has been called.
**
** This routine is defined here in vdbe.c because it depends on knowing
** the internals of the sqlite_func structure which is only defined in that
** one source file.
*/
int sqlite_aggregate_count(sqlite_func *p){
assert( p && p->pFunc && p->pFunc->xStep );
return p->cnt;
}
/*
** Reset an Agg structure. Delete all its contents.
**
** For user-defined aggregate functions, if the step function has been
** called, make sure the finalizer function has also been called. The
** finalizer might need to free memory that was allocated as part of its
** private context. If the finalizer has not been called yet, call it
** now.
*/
static void AggReset(Agg *pAgg){
int i;
HashElem *p;
for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){
AggElem *pElem = sqliteHashData(p);
assert( pAgg->axFinalize!=0 );
assert( pAgg->apFunc!=0 );
for(i=0; i<pAgg->nMem; i++){
if( pElem->aMem[i].s.flags & STK_Dyn ){
if( pAgg->apFunc[i] && (pElem->aMem[i].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.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);
}else if( pAgg->axFinalize[i] && (pElem->aMem[i].s.flags & STK_AggCtx) ){
(pAgg->axFinalize[i])((void*)pElem->aMem[i].z, 0);
}
}
sqliteFree(pElem);
}
sqliteHashClear(&pAgg->hash);
sqliteFree(pAgg->axFinalize);
pAgg->axFinalize = 0;
sqliteFree(pAgg->apFunc);
pAgg->apFunc = 0;
pAgg->pCurrent = 0;
pAgg->pSearch = 0;
pAgg->nMem = 0;
@ -966,8 +1040,8 @@ static char *zOpName[] = { 0,
"SortMakeRec", "SortMakeKey", "Sort", "SortNext",
"SortCallback", "SortReset", "FileOpen", "FileRead",
"FileColumn", "AggReset", "AggFocus", "AggIncr",
"AggNext", "AggSet", "AggGet", "AggFinalizer",
"AggFunc", "SetInsert", "SetFound", "SetNotFound",
"AggNext", "AggSet", "AggGet", "AggFunc",
"AggInit", "SetInsert", "SetFound", "SetNotFound",
"MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
"Goto", "If", "Halt", "ColumnCount",
"ColumnName", "Callback", "NullCallback", "Integer",
@ -1786,14 +1860,16 @@ case OP_Max: {
/* Opcode: UserFunc P1 * P3
**
** Invoke a user function (P3 is a pointer to the function) with
** P1 string arguments taken from the stack. Pop all arguments from
** the stack and push back the result.
** Invoke a user function (P3 is a pointer to a UserFunc structure that
** defines the function) with P1 string arguments taken from the stack.
** Pop all arguments from the stack and push back the result.
**
** See also: AggFunc
*/
case OP_UserFunc: {
int n, i;
UserFuncContext ctx;
void (*xFunc)(void*,int,const char**);
sqlite_func ctx;
n = pOp->p1;
VERIFY( if( n<=0 ) goto bad_instruction; )
VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
@ -1802,10 +1878,12 @@ case OP_UserFunc: {
if( Stringify(p, i) ) goto no_mem;
}
}
xFunc = (void(*)(void*,int,const char**))pOp->p3;
ctx.pFunc = (UserFunc*)pOp->p3;
ctx.s.flags = STK_Null;
ctx.z = 0;
ctx.isError = 0;
xFunc((void*)&ctx, n, (const char**)&zStack[p->tos-n+1]);
ctx.isStep = 0;
(*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]);
PopStack(p, n);
VERIFY( NeedStack(p, p->tos+1); )
p->tos++;
@ -4313,63 +4391,63 @@ case OP_MemLoad: {
case OP_AggReset: {
AggReset(&p->agg);
p->agg.nMem = pOp->p2;
p->agg.axFinalize = sqliteMalloc( p->agg.nMem*sizeof(p->agg.axFinalize[0]) );
p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
break;
}
/* Opcode: AggFinalizer * P2 P3
/* Opcode: AggInit * P2 P3
**
** Register a finializer function for the P2-th column of the aggregate.
** The P3 parameter is a pointer to the finalizer.
** There should be one instance of this opcode immediately following
** each AggReset for each user defined aggregate function that is used
** in a SELECT.
**
** All finalizers must be registered so that user-defined aggregate
** function contexts can be deallocated if the VDBE aborts.
** Initialize the function parameters for a user-defined aggregate function.
** The user-defined aggregate will operate out of aggregate column P2.
** P3 is a pointer to the UserFunc structure for the function.
*/
case OP_AggFinalizer: {
case OP_AggInit: {
int i = pOp->p2;
VERIFY( if( p->agg.nMem<=i ) goto bad_instruction; );
p->agg.axFinalize[i] = (void(*)(void*,void*))pOp->p3;
VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
p->agg.apFunc[i] = (UserFunc*)pOp->p3;
break;
}
/* Opcode: AggFunc * P2 P3
**
** Execute the step function for a user-defined aggregate. The
** function has P2 arguments. P3 is a pointer to the step function.
** function has P2 arguments. P3 is a pointer to the UserFunc
** structure that specifies the user-defined function.
**
** The top of the stack should be the function context. The P2
** parameters occur below the function context on the stack. The
** revised function context remains on the stack after this op-code
** finishes.
** The top of the stack must be an integer which is the index of
** the aggregate column that corresponds to this aggregate function.
** Ideally, this index would be another parameter, but there are
** no free parameters left. The integer is popped from the stack.
*/
case OP_AggFunc: {
int n = pOp->p2;
int i;
void *pCtx;
void *(*xStep)(void*,int,const char**);
Mem *pMem;
sqlite_func ctx;
if( aStack[p->tos].flags & STK_AggCtx ){
pCtx = zStack[p->tos];
}else{
pCtx = 0;
}
VERIFY( if( n<=0 ) goto bad_instruction; )
VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
VERIFY( if( aStack[p->tos].flags!=STK_Int ) goto bad_instruction; )
for(i=p->tos-n; i<p->tos; i++){
if( (aStack[i].flags & STK_Null)==0 ){
if( Stringify(p, i) ) goto no_mem;
}
}
xStep = (void*(*)(void*,int,const char**))pOp->p3;
pCtx = xStep(pCtx, n, (const char**)&zStack[p->tos-n]);
i = aStack[p->tos].i;
VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
ctx.pFunc = (UserFunc*)pOp->p3;
pMem = &p->agg.pCurrent->aMem[i];
ctx.pAgg = pMem->z;
ctx.cnt = ++pMem->s.i;
ctx.isError = 0;
ctx.isStep = 1;
(ctx.pFunc->xStep)(&ctx, n, (const char**)&zStack[p->tos-n]);
pMem->z = ctx.pAgg;
pMem->s.flags = STK_AggCtx;
PopStack(p, n+1);
VERIFY( NeedStack(p, p->tos+1); )
p->tos++;
aStack[p->tos].flags = STK_AggCtx;
zStack[p->tos] = (char*)pCtx;
if( ctx.isError ){
rc = SQLITE_ERROR;
}
break;
}
@ -4517,19 +4595,23 @@ case OP_AggNext: {
pc = pOp->p2 - 1;
} else {
int i;
UserFuncContext ctx;
void *pCtx;
sqlite_func ctx;
Mem *aMem;
int nErr = 0;
p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
aMem = p->agg.pCurrent->aMem;
for(i=0; i<p->agg.nMem; i++){
if( p->agg.axFinalize[i]==0 ) continue;
if( p->agg.apFunc[i]==0 ) continue;
if( p->agg.apFunc[i]->xFinalize==0 ) continue;
if( (aMem[i].s.flags & STK_AggCtx)==0 ) continue;
ctx.s.flags = STK_Null;
ctx.z = 0;
pCtx = (void*)aMem[i].z;
(*p->agg.axFinalize[i])(pCtx, &ctx);
ctx.pAgg = (void*)aMem[i].z;
ctx.cnt = aMem[i].s.i;
ctx.isStep = 0;
ctx.pFunc = p->agg.apFunc[i];
(*p->agg.apFunc[i]->xFinalize)(&ctx);
sqliteFree( aMem[i].z );
aMem[i].s = ctx.s;
aMem[i].z = ctx.z;
if( (aMem[i].s.flags & STK_Str) &&

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.46 2002/02/24 03:25:16 drh Exp $
** $Id: vdbe.h,v 1.47 2002/02/27 19:00:22 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -140,8 +140,8 @@ typedef struct VdbeOp VdbeOp;
#define OP_AggNext 61
#define OP_AggSet 62
#define OP_AggGet 63
#define OP_AggFinalizer 64
#define OP_AggFunc 65
#define OP_AggFunc 64
#define OP_AggInit 65
#define OP_SetInsert 66
#define OP_SetFound 67