]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Completely remove the old SQL function system and replace it with the
authordrh <drh@noemail.net>
Thu, 28 Feb 2002 00:41:10 +0000 (00:41 +0000)
committerdrh <drh@noemail.net>
Thu, 28 Feb 2002 00:41:10 +0000 (00:41 +0000)
new user functions.  The code currently compiles but it coredumps on the
test suite.  Do not use in its present state. (CVS 400)

FossilOrigin-Name: 50797fee5066ec9ea23b720e5ab7e8fc8ccc1988

manifest
manifest.uuid
src/expr.c
src/func.c
src/main.c
src/select.c
src/sqliteInt.h
src/util.c
src/vdbe.c
src/vdbe.h

index 76b44c7facc212dc4fd1f577031a2dee22d67a92..08cd03cf2eff5cee0cd0c714fee6ec4c4cf23505 100644 (file)
--- 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
index 1ea5eee158570dde4b5c319e4cd44bf7c647eed7..df3abacc50a974e19e9463a758726ab618e6a52c 100644 (file)
@@ -1 +1 @@
-c4f9e017b449d4036fa8d2bf77b931d4c31d74f7
\ No newline at end of file
+50797fee5066ec9ea23b720e5ab7e8fc8ccc1988
\ No newline at end of file
index 563291c983225f033682ccb5e7ae90a09f4bc578..ccfc6833d94f04c7bcbf6e12c462ed5caea52edf 100644 (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.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; 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
@@ -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;
-        }
-        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,
@@ -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->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: {
@@ -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; i<pParse->nAgg; 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;
 }
index 881b26ab3c51c2728770c72b38217adedf819765..0f49b549d8653723b2347d66e4133579158c0e2c 100644 (file)
 ** 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.
@@ -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; 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);
+  }
 }
index dfce13aef442993345cb660f7c9af7a24d816535..8ad0d18d32c450322419a1370e7b66b392cd643f 100644 (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.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"
@@ -313,7 +313,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
   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;
@@ -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;
index 2df1b677106d13898480d8a29bbe803de4324c7b..c5f97c0b2e1276ef89cbba2de3984fc2e0e9f781 100644 (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.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; i<pEList->nExpr; 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; 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;
-        }
-      }
     }
   }
 
@@ -1268,36 +1261,20 @@ int sqliteSelect(
     }
     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);
     }
   }
 
index 3734450a555cd434ccb2dd480f972871933a2d45..a39272077a37d082dc91efb600a99fefad2733e0 100644 (file)
@@ -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*);
index b3c3477a26528bf72f758169c9cc8f098577a4d2..dffe611822c1c37af56e1a84423d42d8c1bb2457 100644 (file)
@@ -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 <stdarg.h>
@@ -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;
index 0d134ae0397cd64b4c94a4f9fe5db2473f8c5f0f..a65ff35b81b3c7afbb401c226ae09710cd89a924 100644 (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.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>
@@ -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; 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) &&
index bb2bf2fbe845d121fbaef4c1e61f05b85b7bcded..8d26764eb8c8548343f97ef693ac851a25d69a36 100644 (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.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