Add the sqlite3_set_auxdata() and sqlite3_get_auxdata() APIs. (CVS 1532)

FossilOrigin-Name: c2899b437366d879258ab4f6ae47868441010eca
diff --git a/src/expr.c b/src/expr.c
index 12dbd99..b3ba9f4 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.133 2004/05/30 01:38:43 drh Exp $
+** $Id: expr.c,v 1.134 2004/06/05 10:22:17 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1231,11 +1231,16 @@
       FuncDef *pDef;
       int nId;
       const char *zId;
+      int p2 = 0;
+      int i;
       getFunctionName(pExpr, &zId, &nId);
       pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, 0);
       assert( pDef!=0 );
       nExpr = sqlite3ExprCodeExprList(pParse, pList);
-      sqlite3VdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_FUNCDEF);
+      for(i=0; i<nExpr && i<32; i++){
+        p2 &= (1<<i);
+      }
+      sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
       break;
     }
     case TK_SELECT: {
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 5243e94..e710ada 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.91 2004/06/02 01:22:02 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.92 2004/06/05 10:22:18 danielk1977 Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -915,6 +915,35 @@
 void *sqlite3_user_data(sqlite3_context*);
 
 /*
+** The following two functions may be used by scalar user functions to
+** associate meta-data with argument values. If the same value is passed to
+** multiple invocations of the user-function during query execution, under
+** some circumstances the associated meta-data may be preserved. This may
+** be used, for example, to add a regular-expression matching scalar
+** function. The compiled version of the regular expression is stored as
+** meta-data associated with the SQL value passed as the regular expression
+** pattern.
+**
+** Calling sqlite3_get_auxdata() returns a pointer to the meta data
+** associated with the Nth argument value to the current user function
+** call, where N is the second parameter. If no meta-data has been set for
+** that value, then a NULL pointer is returned.
+**
+** The sqlite3_set_auxdata() is used to associate meta data with a user
+** function argument. The third parameter is a pointer to the meta data
+** to be associated with the Nth user function argument value. The fourth
+** parameter specifies a 'delete function' that will be called on the meta
+** data pointer to release it when it is no longer required. If the delete
+** function pointer is NULL, it is not invoked.
+**
+** In practice, meta-data is preserved between function calls for
+** expressions that are constant at compile time. This includes literal
+** values and SQL variables.
+*/
+void *sqlite3_get_auxdata(sqlite3_context*, int);
+void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
+
+/*
 ** User-defined functions invoke the following routines in order to
 ** set their return value.
 */
diff --git a/src/vdbe.c b/src/vdbe.c
index dfc2560..29ac27c 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.357 2004/06/04 06:22:02 danielk1977 Exp $
+** $Id: vdbe.c,v 1.358 2004/06/05 10:22:18 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1218,11 +1218,18 @@
   break;
 }
 
-/* Opcode: Function P1 * P3
+/* Opcode: Function P1 P2 P3
 **
 ** 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.
+** defines the function) with P1 arguments taken from the stack.  Pop all
+** arguments from the stack and push back the result.
+**
+** P2 is a 32-bit bitmask indicating whether or not each argument to the 
+** function was determined to be constant at compile time. If the first
+** argument was constant then bit 0 of P2 is set. This is used to determine
+** whether meta data associated with a user function argument using the
+** sqlite3_set_auxdata() API may be safely retained until the next
+** invocation of this opcode.
 **
 ** See also: AggFunc
 */
@@ -1243,7 +1250,15 @@
     storeTypeInfo(pArg, db->enc);
   }
 
-  ctx.pFunc = (FuncDef*)pOp->p3;
+  assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC );
+  if( pOp->p3type==P3_FUNCDEF ){
+    ctx.pFunc = (FuncDef*)pOp->p3;
+    ctx.pVdbeFunc = 0;
+  }else{
+    ctx.pVdbeFunc = (VdbeFunc*)pOp->p3;
+    ctx.pFunc = ctx.pVdbeFunc->pFunc;
+  }
+
   ctx.s.flags = MEM_Null;
   ctx.s.z = 0;
   ctx.isError = 0;
@@ -1253,6 +1268,22 @@
   if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
   popStack(&pTos, n);
 
+  /* If any auxilary data functions have been called by this user function,
+  ** immediately call the destructor for any non-static values.
+  */
+  if( ctx.pVdbeFunc ){
+    int mask = pOp->p2;
+    for(i=0; i<n; i++){
+      struct AuxData *pAux = &ctx.pVdbeFunc->apAux[i];
+      if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){
+        pAux->xDelete(pAux->pAux);
+        pAux->pAux = 0;
+      }
+    }
+    pOp->p3 = (char *)ctx.pVdbeFunc;
+    pOp->p3type = P3_VDBEFUNC;
+  }
+
   /* Copy the result of the function to the top of the stack */
   pTos++;
   *pTos = ctx.s;
diff --git a/src/vdbe.h b/src/vdbe.h
index b093f30..1f5f810 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.84 2004/05/26 16:54:48 drh Exp $
+** $Id: vdbe.h,v 1.85 2004/06/05 10:22:18 danielk1977 Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -71,6 +71,7 @@
 #define P3_COLLSEQ  (-4)  /* P3 is a pointer to a CollSeq structure */
 #define P3_FUNCDEF  (-5)  /* P3 is a pointer to a FuncDef structure */
 #define P3_KEYINFO  (-6)  /* P3 is a pointer to a KeyInfo structure */
+#define P3_VDBEFUNC (-7)  /* P3 is a pointer to a VdbeFunc structure */
 
 /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
 ** is made.  That copy is freed when the Vdbe is finalized.  But if the
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 40c8fa8..9512d42 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -177,6 +177,16 @@
 */
 #define MEM_AggCtx    0x0400  /* Mem.z points to an agg function context */
 
+struct VdbeFunc {
+  FuncDef *pFunc;
+  int nAux;
+  struct AuxData {
+    void *pAux;
+    void (*xDelete)(void *);
+  } apAux[0];
+};
+typedef struct VdbeFunc VdbeFunc;
+
 /*
 ** The "context" argument for a installable function.  A pointer to an
 ** instance of this structure is the first argument to the routines used
@@ -192,6 +202,7 @@
 */
 struct sqlite3_context {
   FuncDef *pFunc;   /* Pointer to function information.  MUST BE FIRST */
+  VdbeFunc *pVdbeFunc;  /* Auxilary data, if created. */
   Mem s;            /* The return value is stored here */
   void *pAgg;       /* Aggregate context */
   u8 isError;       /* Set to true for an error */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 6c68598..1e40fad 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -218,6 +218,47 @@
 }
 
 /*
+** Return the auxilary data pointer, if any, for the iArg'th argument to
+** the user-function defined by pCtx.
+*/
+void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
+  VdbeFunc *pVdbeFunc = pCtx->pVdbeFunc;
+  if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
+    return 0;
+  }
+  return pCtx->pVdbeFunc->apAux[iArg].pAux;
+}
+
+/*
+** Set the auxilary data pointer and delete function, for the iArg'th
+** argument to the user-function defined by pCtx. Any previous value is
+** deleted by calling the delete function specified when it was set.
+*/
+void sqlite3_set_auxdata(
+  sqlite3_context *pCtx, 
+  int iArg, 
+  void *pAux, 
+  void (*xDelete)(void*)
+){
+  struct AuxData *pAuxData;
+  if( iArg<0 ) return;
+
+  if( !pCtx->pVdbeFunc || pCtx->pVdbeFunc->nAux<=iArg ){
+    int nMalloc = sizeof(VdbeFunc)+sizeof(struct AuxData)*(iArg+1);
+    pCtx->pVdbeFunc = sqliteRealloc(pCtx->pVdbeFunc, nMalloc);
+    if( !pCtx->pVdbeFunc ) return;
+    pCtx->pVdbeFunc->nAux = iArg+1;
+  }
+
+  pAuxData = &pCtx->pVdbeFunc->apAux[iArg];
+  if( pAuxData->pAux && pAuxData->xDelete ){
+    pAuxData->xDelete(pAuxData->pAux);
+  }
+  pAuxData->pAux = pAux;
+  pAuxData->xDelete = xDelete;
+}
+
+/*
 ** Return the number of times the Step function of a aggregate has been 
 ** called.
 **
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 4c34394..d3a982a 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1234,6 +1234,16 @@
     if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){
       sqliteFree(pOp->p3);
     }
+    if( pOp->p3type==P3_VDBEFUNC ){
+      VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
+      for(i=0; i<pVdbeFunc->nAux; i++){
+        struct AuxData *pAuxData = &pVdbeFunc->apAux[i].pAux;
+        if( pAuxData->pAux && pAuxData->xDelete ){
+          pAuxData->xDelete(pAuxData->pAux);
+        }
+      }
+      sqliteFree(pVdbeFunc);
+    }
 #ifndef NDEBUG
     sqliteFree(pOp->zComment);
 #endif