diff --git a/manifest b/manifest index 76b44c7fac..08cd03cf2e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 @@ -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 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 @@ -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 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 @@ -50,9 +50,9 @@ F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e 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 @@ -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 633951f0fa11c91f93aa2862df84691750c01e73 -R 1ad564fc9fb52e423ae79061556e1e37 +P c4f9e017b449d4036fa8d2bf77b931d4c31d74f7 +R 8c438145064b7ce85d82d8ac4ca5e8e8 U drh -Z 9b3029f554c840c37489da7d32038cb8 +Z 324db426e1592b4f7c305e457c298b2e diff --git a/manifest.uuid b/manifest.uuid index 1ea5eee158..df3abacc50 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c4f9e017b449d4036fa8d2bf77b931d4c31d74f7 \ No newline at end of file +50797fee5066ec9ea23b720e5ab7e8fc8ccc1988 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 563291c983..ccfc6833d9 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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.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" @@ -631,47 +631,6 @@ int sqliteExprResolveIds( 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; in - && 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 @@ -686,67 +645,24 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ 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; + 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; } - 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; - } - default: break; + }else{ + is_agg = pDef->xFunc==0; } if( is_agg && !allowAgg ){ sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1, @@ -759,16 +675,6 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ 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, @@ -943,74 +849,20 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ } case TK_AGG_FUNCTION: { sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); - if( pExpr->iColumn==FN_Avg ){ - assert( pParse->iAggCount>=0 && pParse->iAggCountnAgg ); - 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; inExpr; 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; inExpr; 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; inExpr; 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; inExpr; 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: { @@ -1315,21 +1167,6 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ 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; inAgg; i++){ if( !aAgg[i].isAgg ) continue; @@ -1342,12 +1179,8 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ 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; @@ -1374,10 +1207,10 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ /* ** 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 @@ -1387,15 +1220,15 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ ** 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; @@ -1416,7 +1249,7 @@ UserFunc *sqliteFindUserFunction( 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; } diff --git a/src/func.c b/src/func.c index 881b26ab3c..0f49b549d8 100644 --- a/src/func.c +++ b/src/func.c @@ -16,12 +16,130 @@ ** 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 #include #include -#include "sqlite.h" +#include +#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; i0 ){ + 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; i30 ) 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. @@ -117,7 +235,100 @@ static void stdDevFinalize(sqlite_func *context){ } } +/* +** 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 @@ -125,9 +336,43 @@ static void stdDevFinalize(sqlite_func *context){ ** 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; iidxHash, 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; @@ -416,14 +416,14 @@ void sqlite_close(sqlite *db){ 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); } @@ -646,9 +646,9 @@ int sqlite_create_function( 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; @@ -664,9 +664,9 @@ int sqlite_create_aggregate( 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; diff --git a/src/select.c b/src/select.c index 2df1b67710..c5f97c0b2e 100644 --- a/src/select.c +++ b/src/select.c @@ -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.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" @@ -78,7 +78,6 @@ static void sqliteAggregateInfoReset(Parse *pParse){ sqliteFree(pParse->aAgg); pParse->aAgg = 0; pParse->nAgg = 0; - pParse->iAggCount = -1; pParse->useAgg = 0; } @@ -847,8 +846,14 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ 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; @@ -1151,7 +1156,7 @@ int sqliteSelect( */ sqliteAggregateInfoReset(pParse); if( isAgg ){ - assert( pParse->nAgg==0 && pParse->iAggCount<0 ); + assert( pParse->nAgg==0 ); for(i=0; inExpr; i++){ if( sqliteExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){ goto select_end; @@ -1198,27 +1203,15 @@ int sqliteSelect( if( isAgg ){ sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg); for(i=0; inAgg; 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; inAgg; 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; - } - } } } @@ -1268,36 +1261,20 @@ int sqliteSelect( } for(i=0; inAgg; 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; jpList->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; jpList->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); } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3734450a55..a39272077a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** 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" @@ -127,21 +127,6 @@ extern int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ */ #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 */ @@ -158,7 +143,7 @@ typedef struct WhereInfo WhereInfo; 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 @@ -177,7 +162,7 @@ struct sqlite { 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 */ @@ -200,18 +185,18 @@ struct sqlite { #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 */ }; /* @@ -510,7 +495,7 @@ struct Select { 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 */ }; /* @@ -541,7 +526,6 @@ struct Parse { 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 @@ -652,5 +636,5 @@ Expr *sqliteExprDup(Expr*); 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*); diff --git a/src/util.c b/src/util.c index b3c3477a26..dffe611822 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** 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 @@ -659,8 +659,14 @@ static int isNum(const char *z){ */ 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; diff --git a/src/vdbe.c b/src/vdbe.c index 0d134ae039..a65ff35b81 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.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 @@ -140,14 +140,14 @@ typedef struct Mem Mem; /* 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. @@ -158,7 +158,7 @@ typedef struct Mem Mem; ** (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 */ @@ -181,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 */ - UserFunc **apFunc; /* Information about user-defined aggregate functions */ + FuncDef **apFunc; /* Information about aggregate functions */ }; struct AggElem { char *zKey; /* The key to this AggElem */ @@ -523,7 +523,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){ } /* -** 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 @@ -628,8 +628,8 @@ void *sqlite_aggregate_context(sqlite_func *p, int nByte){ } /* -** 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 @@ -643,7 +643,7 @@ int sqlite_aggregate_count(sqlite_func *p){ /* ** 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 @@ -1061,7 +1061,7 @@ static char *zOpName[] = { 0, "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", - "Noop", "Strlen", "Substr", "UserFunc", + "Noop", "Strlen", "Substr", "Function", "Limit", }; @@ -1865,15 +1865,15 @@ case OP_Max: { 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; @@ -1885,7 +1885,7 @@ case OP_UserFunc: { 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; @@ -4404,22 +4404,22 @@ case OP_AggReset: { /* 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. @@ -4442,7 +4442,7 @@ case OP_AggFunc: { } 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; @@ -4609,17 +4609,21 @@ case OP_AggNext: { p->agg.pCurrent = sqliteHashData(p->agg.pSearch); aMem = p->agg.pCurrent->aMem; for(i=0; iagg.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) && diff --git a/src/vdbe.h b/src/vdbe.h index bb2bf2fbe8..8d26764eb8 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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.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_ @@ -202,7 +202,7 @@ typedef struct VdbeOp VdbeOp; #define OP_Noop 117 #define OP_Strlen 118 #define OP_Substr 119 -#define OP_UserFunc 120 +#define OP_Function 120 #define OP_Limit 121