aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2004-06-05 10:22:17 +0000
committerdanielk1977 <danielk1977@noemail.net>2004-06-05 10:22:17 +0000
commit682f68b0204b543a01f36172ca2bb04d9b629c39 (patch)
tree942fab2d80c2fe9ad461688b72012273be12ccf9 /src
parent2a02e339507e6a299002f30779de27f1da236a17 (diff)
downloadsqlite-682f68b0204b543a01f36172ca2bb04d9b629c39.tar.gz
sqlite-682f68b0204b543a01f36172ca2bb04d9b629c39.zip
Add the sqlite3_set_auxdata() and sqlite3_get_auxdata() APIs. (CVS 1532)
FossilOrigin-Name: c2899b437366d879258ab4f6ae47868441010eca
Diffstat (limited to 'src')
-rw-r--r--src/expr.c9
-rw-r--r--src/sqlite.h.in31
-rw-r--r--src/vdbe.c41
-rw-r--r--src/vdbe.h3
-rw-r--r--src/vdbeInt.h11
-rw-r--r--src/vdbeapi.c41
-rw-r--r--src/vdbeaux.c10
7 files changed, 137 insertions, 9 deletions
diff --git a/src/expr.c b/src/expr.c
index 12dbd9992..b3ba9f47f 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 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
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 5243e94a0..e710ada5d 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_aggregate_context(sqlite3_context*, int nBytes);
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 dfc25601d..29ac27cff 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 @@ divide_by_zero:
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 @@ case OP_Function: {
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 @@ case OP_Function: {
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 b093f3082..1f5f8108d 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 @@ typedef struct VdbeOpList VdbeOpList;
#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 40c8fa8ac..9512d4231 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -177,6 +177,16 @@ typedef struct Mem Mem;
*/
#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 @@ typedef struct Mem Mem;
*/
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 6c685985e..1e40fad75 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -218,6 +218,47 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
}
/*
+** 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 4c343946c..d3a982ad6 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1234,6 +1234,16 @@ void sqlite3VdbeDelete(Vdbe *p){
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