diff options
author | danielk1977 <danielk1977@noemail.net> | 2004-06-05 10:22:17 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2004-06-05 10:22:17 +0000 |
commit | 682f68b0204b543a01f36172ca2bb04d9b629c39 (patch) | |
tree | 942fab2d80c2fe9ad461688b72012273be12ccf9 /src | |
parent | 2a02e339507e6a299002f30779de27f1da236a17 (diff) | |
download | sqlite-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.c | 9 | ||||
-rw-r--r-- | src/sqlite.h.in | 31 | ||||
-rw-r--r-- | src/vdbe.c | 41 | ||||
-rw-r--r-- | src/vdbe.h | 3 | ||||
-rw-r--r-- | src/vdbeInt.h | 11 | ||||
-rw-r--r-- | src/vdbeapi.c | 41 | ||||
-rw-r--r-- | src/vdbeaux.c | 10 |
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 |