-C Try\sto\sreduce\sthe\snumber\sof\smalloc()\sfor\suser-defined\sfunctions.\s\sBegin\ntransfering\sbuilt-in\sfunctions\sover\sto\sthe\suser-define\sfunction\nmechanism.\s(CVS\s399)
-D 2002-02-27T19:50:59
+C Completely\sremove\sthe\sold\sSQL\sfunction\ssystem\sand\sreplace\sit\swith\sthe\nnew\suser\sfunctions.\s\sThe\scode\scurrently\scompiles\sbut\sit\scoredumps\son\sthe\ntest\ssuite.\s\sDo\snot\suse\sin\sits\spresent\sstate.\s(CVS\s400)
+D 2002-02-28T00:41:10
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 7ada2426caba70cb1072ba268bedb694b5018065
F src/delete.c 950d8f9097361419f1963875f9943344b469cf02
-F src/expr.c ea2209a6bdefea23db988b470fc16dbf9d5b3a5a
-F src/func.c 3aeff18b277d9fdece117497dfff8119113ea412
+F src/expr.c 32a2b5826b892a61e153df0ff5778e01d1ba9ad9
+F src/func.c 709784ce09c6156c52cbf860f6bcc7c2349d0b65
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
F src/insert.c 164d2d5e943268a8ff0594e1947599e04df0ce11
-F src/main.c 98f6c6f288e8c9e986634504d9882f348a56edb6
+F src/main.c 5651146585ae613e759fcf372ee064e4940c2463
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
F src/parse.y fc460cda6f475beae963c7f9c737cf13f44f3420
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c a8e90e8f8366b72830010dd6a9bfbf121d2e9370
+F src/select.c 0aeaf678ba3621b0bb11c220892321d29cfe15aa
F src/shell.c 9f8249ca5b8f8aad40becd778c151b58c0d6109e
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in a9b5772604265f98f3120573ef29e37b9d917216
-F src/sqliteInt.h 4e746aa13c5fa39a31a89b73afcd33fa164e8b4f
+F src/sqliteInt.h 9cd512d5be2d2838950e5ace7f92e14ab4804e70
F src/table.c 203a09d5d0009eeeb1f670370d52b4ce163a3b52
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 4b5d30590a744b9bb5605a92d1f620ab2e7e75af
F src/update.c 18971d265b0341574b7e3f73116e7947ddab0997
-F src/util.c 40a12067fa7b18c7e0461b3256b1353c755b59ac
-F src/vdbe.c d1efbaf24a745cf895432baf7642846e34a60f40
-F src/vdbe.h 785b2f175f8be2af285d137125f30042ce8a53b5
+F src/util.c 1c01f0a54a77ae9fb638d026d18093ee1b61e3b3
+F src/vdbe.c 1c16db3ba6222e3ae04cf4461305c6828ff6d018
+F src/vdbe.h 8ab845e63e196e8eb5e51ce69f43b233e51db07e
F src/where.c 664be01b0ce9ffaecbde609afbd4d8d3e5ed1585
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 633951f0fa11c91f93aa2862df84691750c01e73
-R 1ad564fc9fb52e423ae79061556e1e37
+P c4f9e017b449d4036fa8d2bf77b931d4c31d74f7
+R 8c438145064b7ce85d82d8ac4ca5e8e8
U drh
-Z 9b3029f554c840c37489da7d32038cb8
+Z 324db426e1592b4f7c305e457c298b2e
-c4f9e017b449d4036fa8d2bf77b931d4c31d74f7
\ No newline at end of file
+50797fee5066ec9ea23b720e5ab7e8fc8ccc1988
\ No newline at end of file
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.48 2002/02/27 19:00:21 drh Exp $
+** $Id: expr.c,v 1.49 2002/02/28 00:41:10 drh Exp $
*/
#include "sqliteInt.h"
return 0;
}
-#if 0 /* NOT USED */
-/*
-** Compare a token against a string. Return TRUE if they match.
-*/
-static int sqliteTokenCmp(Token *pToken, const char *zStr){
- int n = strlen(zStr);
- if( n!=pToken->n ) return 0;
- return sqliteStrNICmp(pToken->z, zStr, n)==0;
-}
-#endif
-
-/*
-** Convert a function name into its integer identifier. Return the
-** identifier. Return FN_Unknown if the function name is unknown.
-*/
-int sqliteFuncId(Token *pToken){
- static const struct {
- char *zName;
- int len;
- int id;
- } aFunc[] = {
- { "count", 5, FN_Count },
- { "min", 3, FN_Min },
- { "max", 3, FN_Max },
- { "sum", 3, FN_Sum },
- { "avg", 3, FN_Avg },
- { "length", 6, FN_Length },
- { "substr", 6, FN_Substr },
- { "abs", 3, FN_Abs },
- { "round", 5, FN_Round },
- };
- int i;
- for(i=0; i<ArraySize(aFunc); i++){
- if( aFunc[i].len==pToken->n
- && sqliteStrNICmp(pToken->z, aFunc[i].zName, aFunc[i].len)==0 ){
- return aFunc[i].id;
- }
- }
- return FN_Unknown;
-}
-
/*
** Error check the functions in an expression. Make sure all
** function names are recognized and all functions have the correct
if( pExpr==0 ) return 0;
switch( pExpr->op ){
case TK_FUNCTION: {
- int id = sqliteFuncId(&pExpr->token);
int n = pExpr->pList ? pExpr->pList->nExpr : 0;
int no_such_func = 0;
- int too_many_args = 0;
- int too_few_args = 0;
int wrong_num_args = 0;
int is_agg = 0;
int i;
- pExpr->iColumn = id;
- switch( id ){
- case FN_Unknown: {
- UserFunc *pUser = sqliteFindUserFunction(pParse->db,
- pExpr->token.z, pExpr->token.n, n, 0);
- if( pUser==0 ){
- pUser = sqliteFindUserFunction(pParse->db,
- pExpr->token.z, pExpr->token.n, -1, 0);
- if( pUser==0 ){
- no_such_func = 1;
- }else{
- wrong_num_args = 1;
- }
- }else{
- is_agg = pUser->xFunc==0;
- }
- break;
- }
- case FN_Count: {
- too_many_args = n>1;
- is_agg = 1;
- break;
- }
- case FN_Max:
- case FN_Min: {
- too_few_args = n<1;
- is_agg = n==1;
- break;
- }
- case FN_Avg:
- case FN_Sum: {
- too_many_args = n>1;
- too_few_args = n<1;
- is_agg = 1;
- break;
- }
- case FN_Abs:
- case FN_Length: {
- too_few_args = n<1;
- too_many_args = n>1;
- break;
- }
- case FN_Round: {
- too_few_args = n<1;
- too_many_args = n>2;
- break;
- }
- case FN_Substr: {
- too_few_args = n<3;
- too_many_args = n>3;
- break;
+ FuncDef *pDef;
+
+ pDef = sqliteFindFunction(pParse->db, pExpr->token.z, pExpr->token.n,n,0);
+ if( pDef==0 ){
+ pDef = sqliteFindFunction(pParse->db,
+ pExpr->token.z, pExpr->token.n, -1, 0);
+ if( pDef==0 ){
+ no_such_func = 1;
+ }else{
+ wrong_num_args = 1;
}
- default: break;
+ }else{
+ is_agg = pDef->xFunc==0;
}
if( is_agg && !allowAgg ){
sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1,
pExpr->token.z, pExpr->token.n, 0);
pParse->nErr++;
nErr++;
- }else if( too_many_args ){
- sqliteSetNString(&pParse->zErrMsg, "too many arguments to function ",-1,
- pExpr->token.z, pExpr->token.n, "()", 2, 0);
- pParse->nErr++;
- nErr++;
- }else if( too_few_args ){
- sqliteSetNString(&pParse->zErrMsg, "too few arguments to function ",-1,
- pExpr->token.z, pExpr->token.n, "()", 2, 0);
- pParse->nErr++;
- nErr++;
}else if( wrong_num_args ){
sqliteSetNString(&pParse->zErrMsg,
"wrong number of arguments to function ",-1,
}
case TK_AGG_FUNCTION: {
sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
- if( pExpr->iColumn==FN_Avg ){
- assert( pParse->iAggCount>=0 && pParse->iAggCount<pParse->nAgg );
- sqliteVdbeAddOp(v, OP_AggGet, 0, pParse->iAggCount);
- sqliteVdbeAddOp(v, OP_Divide, 0, 0);
- }
break;
}
case TK_FUNCTION: {
- int id = pExpr->iColumn;
- int op;
int i;
ExprList *pList = pExpr->pList;
- switch( id ){
- case FN_Min:
- case FN_Max: {
- op = id==FN_Min ? OP_Min : OP_Max;
- for(i=0; i<pList->nExpr; i++){
- sqliteExprCode(pParse, pList->a[i].pExpr);
- if( i>0 ){
- sqliteVdbeAddOp(v, op, 0, 0);
- }
- }
- break;
- }
- case FN_Abs: {
- sqliteExprCode(pParse, pList->a[0].pExpr);
- sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
- break;
- }
- case FN_Round: {
- if( pList->nExpr==2 ){
- sqliteExprCode(pParse, pList->a[1].pExpr);
- }else{
- sqliteVdbeAddOp(v, OP_Integer, 0, 0);
- }
- sqliteExprCode(pParse, pList->a[0].pExpr);
- sqliteVdbeAddOp(v, OP_Precision, 0, 0);
- break;
- }
- case FN_Length: {
- sqliteExprCode(pParse, pList->a[0].pExpr);
- sqliteVdbeAddOp(v, OP_Strlen, 0, 0);
- break;
- }
- case FN_Substr: {
- for(i=0; i<pList->nExpr; i++){
- sqliteExprCode(pParse, pList->a[i].pExpr);
- }
- sqliteVdbeAddOp(v, OP_Substr, 0, 0);
- break;
- }
- case FN_Unknown: {
- UserFunc *pUser;
- pUser = sqliteFindUserFunction(pParse->db,
+ FuncDef *pDef;
+ pDef = sqliteFindFunction(pParse->db,
pExpr->token.z, pExpr->token.n, pList->nExpr, 0);
- assert( pUser!=0 );
- for(i=0; i<pList->nExpr; i++){
- sqliteExprCode(pParse, pList->a[i].pExpr);
- }
- sqliteVdbeAddOp(v, OP_UserFunc, pList->nExpr, 0);
- sqliteVdbeChangeP3(v, -1, (char*)pUser, P3_POINTER);
- break;
- }
- default: {
- /* Can't happen! */
- break;
- }
+ assert( pDef!=0 );
+ for(i=0; i<pList->nExpr; i++){
+ sqliteExprCode(pParse, pList->a[i].pExpr);
}
+ sqliteVdbeAddOp(v, OP_Function, pList->nExpr, 0);
+ sqliteVdbeChangeP3(v, -1, (char*)pDef, P3_POINTER);
break;
}
case TK_SELECT: {
break;
}
case TK_AGG_FUNCTION: {
- if( pExpr->iColumn==FN_Count || pExpr->iColumn==FN_Avg ){
- if( pParse->iAggCount>=0 ){
- i = pParse->iAggCount;
- }else{
- i = appendAggInfo(pParse);
- if( i<0 ) return 1;
- pParse->aAgg[i].isAgg = 1;
- pParse->aAgg[i].pExpr = 0;
- pParse->iAggCount = i;
- }
- if( pExpr->iColumn==FN_Count ){
- pExpr->iAgg = i;
- break;
- }
- }
aAgg = pParse->aAgg;
for(i=0; i<pParse->nAgg; i++){
if( !aAgg[i].isAgg ) continue;
if( i<0 ) return 1;
pParse->aAgg[i].isAgg = 1;
pParse->aAgg[i].pExpr = pExpr;
- if( pExpr->iColumn==FN_Unknown ){
- pParse->aAgg[i].pUser = sqliteFindUserFunction(pParse->db,
+ pParse->aAgg[i].pFunc = sqliteFindFunction(pParse->db,
pExpr->token.z, pExpr->token.n, pExpr->pList->nExpr, 0);
- }else{
- pParse->aAgg[i].pUser = 0;
- }
}
pExpr->iAgg = i;
break;
/*
** Locate a user function given a name and a number of arguments.
-** Return a pointer to the UserFunc structure that defines that
+** Return a pointer to the FuncDef structure that defines that
** function, or return NULL if the function does not exist.
**
-** If the createFlag argument is true, then a new (blank) UserFunc
+** If the createFlag argument is true, then a new (blank) FuncDef
** structure is created and liked into the "db" structure if a
** no matching function previously existed. When createFlag is true
** and the nArg parameter is -1, then only a function that accepts
** function found is returned. A function is valid if either xFunc
** or xStep is non-zero.
*/
-UserFunc *sqliteFindUserFunction(
+FuncDef *sqliteFindFunction(
sqlite *db, /* An open database */
const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */
int createFlag /* Create new entry if true and does not otherwise exist */
){
- UserFunc *pFirst, *p, *pMaybe;
- pFirst = p = (UserFunc*)sqliteHashFind(&db->userFunc, zName, nName);
+ FuncDef *pFirst, *p, *pMaybe;
+ pFirst = p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, nName);
if( p && !createFlag && nArg<0 ){
while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
return p;
p = sqliteMalloc( sizeof(*p) );
p->nArg = nArg;
p->pNext = pFirst;
- sqliteHashInsert(&db->userFunc, zName, nName, (void*)p);
+ sqliteHashInsert(&db->aFunc, zName, nName, (void*)p);
}
return p;
}
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.5 2002/02/27 19:50:59 drh Exp $
+** $Id: func.c,v 1.6 2002/02/28 00:41:10 drh Exp $
*/
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
-#include "sqlite.h"
+#include <assert.h>
+#include "sqliteInt.h"
+
+/*
+** Implementation of the non-aggregate min() and max() functions
+*/
+static void minFunc(sqlite_func *context, int argc, const char **argv){
+ const char *zBest;
+ int i;
+
+ zBest = argv[0];
+ for(i=1; i<argc; i++){
+ if( sqliteCompare(argv[i], zBest)<0 ){
+ zBest = argv[i];
+ }
+ }
+ sqlite_set_result_string(context, zBest, -1);
+}
+static void maxFunc(sqlite_func *context, int argc, const char **argv){
+ const char *zBest;
+ int i;
+
+ zBest = argv[0];
+ for(i=1; i<argc; i++){
+ if( sqliteCompare(argv[i], zBest)>0 ){
+ zBest = argv[i];
+ }
+ }
+ sqlite_set_result_string(context, zBest, -1);
+}
+
+/*
+** Implementation of the length() function
+*/
+static void lengthFunc(sqlite_func *context, int argc, const char **argv){
+ const char *z;
+ int len;
+
+ assert( argc==1 );
+ z = argv[0];
+ if( z==0 ){
+ len = 0;
+ }else{
+#ifdef SQLITE_UTF8
+ for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
+#else
+ len = strlen(z);
+#endif
+ }
+ sqlite_set_result_int(context, len);
+}
+
+/*
+** Implementation of the abs() function
+*/
+static void absFunc(sqlite_func *context, int argc, const char **argv){
+ const char *z;
+ assert( argc==1 );
+ z = argv[0];
+ if( z && z[0]=='-' && isdigit(z[1]) ) z++;
+ sqlite_set_result_string(context, z, -1);
+}
+
+/*
+** Implementation of the substr() function
+*/
+static void substrFunc(sqlite_func *context, int argc, const char **argv){
+ const char *z;
+#ifdef SQLITE_UTF8
+ const char *z2;
+ int i;
+#endif
+ int p1, p2, len;
+ assert( argc==3 );
+ z = argv[0];
+ if( z==0 ) return;
+ p1 = atoi(argv[1]?argv[1]:0);
+ p2 = atoi(argv[2]?argv[2]:0);
+#ifdef SQLITE_UTF8
+ for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z)!=0x80 ) len++; }
+#else
+ len = strlen(z);
+#endif
+ if( p1<0 ){
+ p1 = len-p1;
+ }else if( p1>0 ){
+ p1--;
+ }
+ if( p1+p2>len ){
+ p2 = len-p1;
+ }
+#ifdef SQLITE_UTF8
+ for(i=0; i<p1; i++){
+ assert( z[i] );
+ if( (z[i]&0xc0)!=0x80 ) p1++;
+ }
+ for(; i<p1+p2; i++){
+ assert( z[i] );
+ if( (z[i]&0xc0)!=0x80 ) p2++;
+ }
+#endif
+ sqlite_set_result_string(context, &z[p1], p2);
+}
+
+/*
+** Implementation of the round() function
+*/
+static void roundFunc(sqlite_func *context, int argc, const char **argv){
+ int n;
+ double r;
+ char zBuf[100];
+ assert( argc==1 || argc==2 );
+ n = argc==2 && argv[1] ? atoi(argv[1]) : 0;
+ if( n>30 ) n = 30;
+ if( n<0 ) n = 0;
+ r = argv[0] ? atof(argv[0]) : 0.0;
+ sprintf(zBuf,"%.*f",n,r);
+ sqlite_set_result_string(context, zBuf, -1);
+}
/*
** Implementation of the upper() and lower() SQL functions.
}
}
+/*
+** The following structure keeps track of state information for the
+** count() aggregate function.
+*/
+typedef struct CountCtx CountCtx;
+struct CountCtx {
+ int n;
+};
+/*
+** Routines to implement the count() aggregate function.
+*/
+static void countStep(sqlite_func *context, int argc, const char **argv){
+ CountCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( (argc==0 || argv[0]) && p ){
+ p->n++;
+ }
+}
+static void countFinalize(sqlite_func *context){
+ CountCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p ){
+ sqlite_set_result_int(context, p->n);
+ }
+}
+
+/*
+** This function tracks state information for the min() and max()
+** aggregate functions.
+*/
+typedef struct MinMaxCtx MinMaxCtx;
+struct MinMaxCtx {
+ char *z; /* The best so far */
+ char zBuf[28]; /* Space that can be used for storage */
+};
+
+/*
+** Routines to implement min() and max() aggregate functions.
+*/
+static void minStep(sqlite_func *context, int argc, const char **argv){
+ MinMaxCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p==0 || argc<1 ) return;
+ if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){
+ if( p->z && p->z!=p->zBuf ){
+ sqliteFree(p->z);
+ }
+ if( argv[0] ){
+ int len = strlen(argv[0]);
+ if( len < sizeof(p->zBuf) ){
+ p->z = p->zBuf;
+ }else{
+ p->z = sqliteMalloc( len+1 );
+ if( p->z==0 ) return;
+ }
+ strcpy(p->z, argv[0]);
+ }else{
+ p->z = 0;
+ }
+ }
+}
+static void maxStep(sqlite_func *context, int argc, const char **argv){
+ MinMaxCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p==0 || argc<1 ) return;
+ if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){
+ if( p->z && p->z!=p->zBuf ){
+ sqliteFree(p->z);
+ }
+ if( argv[0] ){
+ int len = strlen(argv[0]);
+ if( len < sizeof(p->zBuf) ){
+ p->z = p->zBuf;
+ }else{
+ p->z = sqliteMalloc( len+1 );
+ if( p->z==0 ) return;
+ }
+ strcpy(p->z, argv[0]);
+ }else{
+ p->z = 0;
+ }
+ }
+}
+static void minMaxFinalize(sqlite_func *context){
+ MinMaxCtx *p;
+ p = sqlite_aggregate_context(context, sizeof(*p));
+ if( p && p->z ){
+ sqlite_set_result_string(context, p->z, strlen(p->z));
+ }
+ if( p && p->z && p->z!=p->zBuf ){
+ sqliteFree(p->z);
+ }
+}
/*
** This function registered all of the above C functions as SQL
** external linkage.
*/
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);
+ static struct {
+ char *zName;
+ int nArg;
+ void (*xFunc)(sqlite_func*,int,const char**);
+ } aFuncs[] = {
+ { "min", -1, minFunc },
+ { "max", -1, maxFunc },
+ { "length", 1, lengthFunc },
+ { "substr", 3, substrFunc },
+ { "abs", 1, absFunc },
+ { "round", 1, roundFunc },
+ { "round", 2, roundFunc },
+ { "upper", 1, upperFunc },
+ { "lower", 1, lowerFunc },
+ };
+ static struct {
+ char *zName;
+ int nArg;
+ void (*xStep)(sqlite_func*,int,const char**);
+ void (*xFinalize)(sqlite_func*);
+ } aAggs[] = {
+ { "min", 1, minStep, minMaxFinalize },
+ { "max", 1, maxStep, minMaxFinalize },
+ { "sum", 1, sumStep, sumFinalize },
+ { "avg", 1, sumStep, avgFinalize },
+ { "count", 0, countStep, countFinalize },
+ { "count", 1, countStep, countFinalize },
+ { "stddev", 1, stdDevStep, stdDevFinalize },
+ };
+ int i;
+
+ for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
+ sqlite_create_function(db, aFuncs[i].zName,
+ aFuncs[i].nArg, aFuncs[i].xFunc, 0);
+ }
+ for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
+ sqlite_create_aggregate(db, aAggs[i].zName,
+ aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0);
+ }
}
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.65 2002/02/27 19:00:22 drh Exp $
+** $Id: main.c,v 1.66 2002/02/28 00:41:11 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
- sqliteHashInit(&db->userFunc, SQLITE_HASH_STRING, 1);
+ sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
sqliteRegisterBuildinFunctions(db);
db->onError = OE_Default;
db->priorNewRowid = 0;
if( db->pBeTemp ){
sqliteBtreeClose(db->pBeTemp);
}
- for(i=sqliteHashFirst(&db->userFunc); i; i=sqliteHashNext(i)){
- UserFunc *pFunc, *pNext;
- for(pFunc = (UserFunc*)sqliteHashData(i); pFunc; pFunc=pNext){
+ for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
+ FuncDef *pFunc, *pNext;
+ for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
pNext = pFunc->pNext;
sqliteFree(pFunc);
}
}
- sqliteHashClear(&db->userFunc);
+ sqliteHashClear(&db->aFunc);
sqliteFree(db);
}
void (*xFunc)(sqlite_func*,int,const char**), /* The implementation */
void *pUserData /* User data */
){
- UserFunc *p;
+ FuncDef *p;
if( db==0 || zName==0 ) return 1;
- p = sqliteFindUserFunction(db, zName, strlen(zName), nArg, 1);
+ p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
if( p==0 ) return 1;
p->xFunc = xFunc;
p->xStep = 0;
void (*xFinalize)(sqlite_func*), /* The finalizer */
void *pUserData /* User data */
){
- UserFunc *p;
+ FuncDef *p;
if( db==0 || zName==0 ) return 1;
- p = sqliteFindUserFunction(db, zName, strlen(zName), nArg, 1);
+ p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
if( p==0 ) return 1;
p->xFunc = 0;
p->xStep = xStep;
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.68 2002/02/27 19:00:22 drh Exp $
+** $Id: select.c,v 1.69 2002/02/28 00:41:11 drh Exp $
*/
#include "sqliteInt.h"
sqliteFree(pParse->aAgg);
pParse->aAgg = 0;
pParse->nAgg = 0;
- pParse->iAggCount = -1;
pParse->useAgg = 0;
}
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0;
- if( pExpr->iColumn!=FN_Min && pExpr->iColumn!=FN_Max ) return 0;
- seekOp = pExpr->iColumn==FN_Min ? OP_Rewind : OP_Last;
+ if( pExpr->token.n!=3 ) return 0;
+ if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){
+ seekOp = OP_Rewind;
+ }else if( sqliteStrNICmp(pExpr->token.z,"max",3)==0 ){
+ seekOp = OP_Last;
+ }else{
+ return 0;
+ }
pExpr = pExpr->pList->a[0].pExpr;
if( pExpr->op!=TK_COLUMN ) return 0;
iCol = pExpr->iColumn;
*/
sqliteAggregateInfoReset(pParse);
if( isAgg ){
- assert( pParse->nAgg==0 && pParse->iAggCount<0 );
+ assert( pParse->nAgg==0 );
for(i=0; i<pEList->nExpr; i++){
if( sqliteExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){
goto select_end;
if( isAgg ){
sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
for(i=0; i<pParse->nAgg; i++){
- UserFunc *pUser;
- if( (pUser = pParse->aAgg[i].pUser)!=0 && pUser->xFinalize!=0 ){
+ FuncDef *pFunc;
+ if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
sqliteVdbeAddOp(v, OP_AggInit, 0, i);
- sqliteVdbeChangeP3(v, -1, (char*)pUser, P3_POINTER);
+ sqliteVdbeChangeP3(v, -1, (char*)pFunc, P3_POINTER);
}
}
if( pGroupBy==0 ){
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeAddOp(v, OP_AggFocus, 0, 0);
- for(i=0; i<pParse->nAgg; i++){
- Expr *pE;
- if( !pParse->aAgg[i].isAgg ) continue;
- pE = pParse->aAgg[i].pExpr;
- assert( pE==0 || pE->op==TK_AGG_FUNCTION );
- assert( pE==0 || (pE->pList!=0 && pE->pList->nExpr==1) );
- if( pE==0 || pE->iColumn==FN_Sum ){
- sqliteVdbeAddOp(v, OP_Integer, 0, 0);
- sqliteVdbeAddOp(v, OP_AggSet, 0, i);
- continue;
- }
- }
}
}
}
for(i=0; i<pParse->nAgg; i++){
Expr *pE;
- int op, j;
+ int j;
if( !pParse->aAgg[i].isAgg ) continue;
pE = pParse->aAgg[i].pExpr;
- if( pE==0 ){
- sqliteVdbeAddOp(v, OP_AggIncr, 1, i);
- continue;
- }
assert( pE->op==TK_AGG_FUNCTION );
- assert( pE->pList!=0 );
- for(j=0; j<pE->pList->nExpr; j++){
- sqliteExprCode(pParse, pE->pList->a[j].pExpr);
- }
- switch( pE->iColumn ){
- case FN_Min: op = OP_Min; break;
- case FN_Max: op = OP_Max; break;
- case FN_Avg: op = OP_Add; break;
- case FN_Sum: op = OP_Add; break;
- 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, P3_POINTER);
+ if( pE->pList ){
+ for(j=0; j<pE->pList->nExpr; j++){
+ sqliteExprCode(pParse, pE->pList->a[j].pExpr);
+ }
}
+ sqliteVdbeAddOp(v, OP_Integer, i, 0);
+ sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList->nExpr);
+ assert( pParse->aAgg[i].pFunc!=0 );
+ assert( pParse->aAgg[i].pFunc->xStep!=0 );
+ sqliteVdbeChangeP3(v, -1, (char*)pParse->aAgg[i].pFunc, P3_POINTER);
}
}
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.95 2002/02/27 19:00:22 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.96 2002/02/28 00:41:11 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
*/
#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
-/*
-** Integer identifiers for built-in SQL functions.
-*/
-#define FN_Unknown 0 /* Not a built-in. Might be user defined */
-#define FN_Count 1
-#define FN_Min 2
-#define FN_Max 3
-#define FN_Sum 4
-#define FN_Avg 5
-#define FN_Fcnt 6
-#define FN_Length 7
-#define FN_Substr 8
-#define FN_Abs 9
-#define FN_Round 10
-
/*
** Forward references to structures
*/
typedef struct WhereLevel WhereLevel;
typedef struct Select Select;
typedef struct AggExpr AggExpr;
-typedef struct UserFunc UserFunc;
+typedef struct FuncDef FuncDef;
/*
** Each database is an instance of the following structure
Hash idxHash; /* All (named) indices indexed by name */
Hash tblDrop; /* Uncommitted DROP TABLEs */
Hash idxDrop; /* Uncommitted DROP INDEXs */
- Hash userFunc; /* User defined functions */
+ Hash aFunc; /* All functions that can be in SQL exprs */
int lastRowid; /* ROWID of most recent insert */
int priorNewRowid; /* Last randomly generated ROWID */
int onError; /* Default conflict algorithm */
#define SQLITE_ResultDetails 0x00000100 /* Details added to result set */
/*
-** Each user-defined function is defined by an instance of the following
-** structure. A pointer to this structure is stored in the sqlite.userFunc
+** Each SQL function is defined by an instance of the following
+** structure. A pointer to this structure is stored in the sqlite.aFunc
** hash table. When multiple functions have the same name, the hash table
** points to a linked list of these structures.
*/
-struct UserFunc {
+struct FuncDef {
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 */
+ FuncDef *pNext; /* Next function with same name */
};
/*
struct AggExpr {
int isAgg; /* if TRUE contains an aggregate function */
Expr *pExpr; /* The expression */
- UserFunc *pUser; /* User-defined aggregate function */
+ FuncDef *pFunc; /* Information about the aggregate function */
};
/*
int nSet; /* Number of sets used so far */
int nAgg; /* Number of aggregate expressions */
AggExpr *aAgg; /* An array of aggregate expressions */
- int iAggCount; /* Index of the count(*) aggregate in aAgg[] */
int useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
int schemaVerified; /* True if an OP_VerifySchema has been coded someplace
ExprList *sqliteExprListDup(ExprList*);
IdList *sqliteIdListDup(IdList*);
Select *sqliteSelectDup(Select*);
-UserFunc *sqliteFindUserFunction(sqlite*,const char*,int,int,int);
+FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
void sqliteRegisterBuildinFunctions(sqlite*);
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
-** $Id: util.c,v 1.38 2002/02/27 01:47:12 drh Exp $
+** $Id: util.c,v 1.39 2002/02/28 00:41:11 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
*/
int sqliteCompare(const char *atext, const char *btext){
int result;
- int isNumA = isNum(atext);
- int isNumB = isNum(btext);
+ int isNumA, isNumB;
+ if( atext==0 ){
+ return -(btext!=0);
+ }else if( btext==0 ){
+ return 1;
+ }
+ isNumA = isNum(atext);
+ isNumB = isNum(btext);
if( isNumA ){
if( !isNumB ){
result = -1;
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.125 2002/02/27 19:50:59 drh Exp $
+** $Id: vdbe.c,v 1.126 2002/02/28 00:41:11 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* The following STK_ value appears only in AggElem.aMem.s.flag fields.
** It indicates that the corresponding AggElem.aMem.z points to a
-** user-defined aggregate context that needs to be finalized.
+** aggregate function context that needs to be finalized.
*/
#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */
/*
-** The "context" argument for a user-defined function. A pointer to an
+** The "context" argument for a installable function. A pointer to an
** instance of this structure is the first argument to the routines used
-** implement user-defined SQL functions.
+** implement the 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.
** (Stack) which are only defined there.
*/
struct sqlite_func {
- UserFunc *pFunc; /* Pointer to function information. MUST BE FIRST */
+ FuncDef *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 */
AggElem *pCurrent; /* The AggElem currently in focus */
HashElem *pSearch; /* The hash element for pCurrent */
Hash hash; /* Hash table of all aggregate elements */
- UserFunc **apFunc; /* Information about user-defined aggregate functions */
+ FuncDef **apFunc; /* Information about aggregate functions */
};
struct AggElem {
char *zKey; /* The key to this AggElem */
}
/*
-** The following group or routines are employed by user-defined functions
+** The following group or routines are employed by installable functions
** to return their results.
**
** The sqlite_set_result_string() routine can be used to return a string
}
/*
-** Return the number of times the Step function of a user-defined
-** aggregate has been called.
+** Return the number of times the Step function of a 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
/*
** Reset an Agg structure. Delete all its contents.
**
-** For user-defined aggregate functions, if the step function has been
+** For installable 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
"Ne", "Lt", "Le", "Gt",
"Ge", "IsNull", "NotNull", "Negative",
"And", "Or", "Not", "Concat",
- "Noop", "Strlen", "Substr", "UserFunc",
+ "Noop", "Strlen", "Substr", "Function",
"Limit",
};
break;
}
-/* Opcode: UserFunc P1 * P3
+/* Opcode: Function P1 * P3
**
-** Invoke a user function (P3 is a pointer to a UserFunc structure that
+** Invoke a user function (P3 is a pointer to a Function 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: {
+case OP_Function: {
int n, i;
sqlite_func ctx;
if( Stringify(p, i) ) goto no_mem;
}
}
- ctx.pFunc = (UserFunc*)pOp->p3;
+ ctx.pFunc = (FuncDef*)pOp->p3;
ctx.s.flags = STK_Null;
ctx.z = 0;
ctx.isError = 0;
/* Opcode: AggInit * P2 P3
**
-** 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.
+** Initialize the function parameters for an aggregate function.
+** The aggregate will operate out of aggregate column P2.
+** P3 is a pointer to the FuncDef structure for the function.
*/
case OP_AggInit: {
int i = pOp->p2;
VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
- p->agg.apFunc[i] = (UserFunc*)pOp->p3;
+ p->agg.apFunc[i] = (FuncDef*)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 UserFunc
-** structure that specifies the user-defined function.
+** Execute the step function for an aggregate. The
+** function has P2 arguments. P3 is a pointer to the FuncDef
+** structure that specifies the function.
**
** The top of the stack must be an integer which is the index of
** the aggregate column that corresponds to this aggregate function.
}
i = aStack[p->tos].i;
VERIFY( if( i<0 || i>=p->agg.nMem ) goto bad_instruction; )
- ctx.pFunc = (UserFunc*)pOp->p3;
+ ctx.pFunc = (FuncDef*)pOp->p3;
pMem = &p->agg.pCurrent->aMem[i];
ctx.z = pMem->s.z;
ctx.pAgg = pMem->z;
p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
aMem = p->agg.pCurrent->aMem;
for(i=0; i<p->agg.nMem; i++){
+ int freeCtx;
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;
ctx.pAgg = (void*)aMem[i].z;
+ freeCtx = aMem[i].z && aMem[i].z!=aMem[i].s.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 );
+ if( freeCtx ){
+ sqliteFree( aMem[i].z );
+ }
aMem[i].s = ctx.s;
aMem[i].z = ctx.z;
if( (aMem[i].s.flags & STK_Str) &&
** 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.47 2002/02/27 19:00:22 drh Exp $
+** $Id: vdbe.h,v 1.48 2002/02/28 00:41:11 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#define OP_Noop 117
#define OP_Strlen 118
#define OP_Substr 119
-#define OP_UserFunc 120
+#define OP_Function 120
#define OP_Limit 121