Add the sqlite3_create_function_v2() API, a version of create_function that allows a destructor to be specified.
FossilOrigin-Name: 9a724dfbe822c77e76721abe3443c9cb018bb2e2
This commit is contained in:
parent
badc980afa
commit
d2199f0f8d
33
manifest
33
manifest
@ -1,8 +1,5 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Refactor\sthe\simplementation\sof\sthe\sscratch\smemory\sallocator.\s\sAdd\sthe\nSQLITE_TESTCTRL_SCRATCHMALLOC\sinterface\sto\sfacilitate\stesting.
|
||||
D 2010-08-27T17:16:45
|
||||
C Add\sthe\ssqlite3_create_function_v2()\sAPI,\sa\sversion\sof\screate_function\sthat\sallows\sa\sdestructor\sto\sbe\sspecified.
|
||||
D 2010-08-27T17:48:52
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -129,7 +126,7 @@ F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
|
||||
F src/expr.c 9ee507c3dc6eaa5657cbd1dad026cdeda89c559f
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 58bbf52c6ddd3f64ca40a3230f9e548a83a5cb16
|
||||
F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341
|
||||
F src/func.c caa6c5134106d95cced4db80ce3fdcdde4f6c8d4
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
@ -139,7 +136,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 6d422ea91cf3d2d00408c5a8f2391cd458da85f8
|
||||
F src/main.c bdd23be253843d3f34faa8f5bd3f92ebbf05b94b
|
||||
F src/main.c 185e558e8e38a36a78fdb36b378571f8fc136a7a
|
||||
F src/malloc.c f34c9253326fcd2dad0041801992ccf18ddd6ab5
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
@ -174,14 +171,14 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 8add6cab889fc02e1492eda8dba462ccf11f51dd
|
||||
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
|
||||
F src/sqlite.h.in 60a40abb36376b4cdf6a9ac7604ed5d3ea2d0bf8
|
||||
F src/sqlite.h.in 55498e6664eecf9a1db722d473445dbd210fe5f7
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h 78ed6bd32777ad06a8b9910d17307aeeae555485
|
||||
F src/sqliteInt.h e3055cc4bd65c6a097b8e9132df807ae683bef9f
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c b1565eb727ec7121b59287fed77fc378118bfb69
|
||||
F src/test1.c 55005c9781b157b1d215ba145768783b9abae78c
|
||||
F src/test1.c 2d3ab2cacced2adfee13a6d93b3570ada4072c39
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
@ -431,6 +428,7 @@ F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f
|
||||
F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f
|
||||
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 0d43ff07970a47e58d37e1fea1ae6a2458e2590f
|
||||
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
|
||||
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
@ -850,14 +848,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 51049479a8577e03cc353f71f6e13a10c8323d91
|
||||
R 9667b04fa2c6e7e750d5c74a6bbee707
|
||||
U drh
|
||||
Z c2de87f687a677d94fa81a950a4c025c
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFMd/MAoxKgR168RlERAvLjAJ9ChwPUiFzrhTLciw7Q4AEhSu2EvACfZWP3
|
||||
sBXwHRcpD05MSHO9+3nFRAQ=
|
||||
=R7/R
|
||||
-----END PGP SIGNATURE-----
|
||||
P a3475ddfbe4526e6e0b334fd1376ee7c31508b80
|
||||
R ce2fe209cb36d8732f735448dc28c68e
|
||||
U dan
|
||||
Z 0f4ca6d40dff81bf94d3eaa37cf31103
|
||||
|
@ -1 +1 @@
|
||||
a3475ddfbe4526e6e0b334fd1376ee7c31508b80
|
||||
9a724dfbe822c77e76721abe3443c9cb018bb2e2
|
@ -1450,10 +1450,10 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
}else{
|
||||
pInfo = (struct compareInfo*)&likeInfoNorm;
|
||||
}
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY,
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0,0);
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
|
||||
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||
setLikeOptFlag(db, "like",
|
||||
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
|
||||
|
76
src/main.c
76
src/main.c
@ -595,11 +595,28 @@ void sqlite3CloseSavepoints(sqlite3 *db){
|
||||
db->isTransactionSavepoint = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke the destructor function associated with FuncDef p, if any. Except,
|
||||
** if this is not the last copy of the function, do not invoke it. Multiple
|
||||
** copies of a single function are created when create_function() is called
|
||||
** with SQLITE_ANY as the encoding.
|
||||
*/
|
||||
static void functionDestroy(sqlite3 *db, FuncDef *p){
|
||||
FuncDestructor *pDestructor = p->pDestructor;
|
||||
if( pDestructor ){
|
||||
pDestructor->nRef--;
|
||||
if( pDestructor->nRef==0 ){
|
||||
pDestructor->xDestroy(pDestructor->pUserData);
|
||||
sqlite3DbFree(db, pDestructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an existing SQLite database
|
||||
*/
|
||||
int sqlite3_close(sqlite3 *db){
|
||||
HashElem *i;
|
||||
HashElem *i; /* Hash table iterator */
|
||||
int j;
|
||||
|
||||
if( !db ){
|
||||
@ -667,6 +684,7 @@ int sqlite3_close(sqlite3 *db){
|
||||
for(p=db->aFunc.a[j]; p; p=pHash){
|
||||
pHash = p->pHash;
|
||||
while( p ){
|
||||
functionDestroy(db, p);
|
||||
pNext = p->pNext;
|
||||
sqlite3DbFree(db, p);
|
||||
p = pNext;
|
||||
@ -941,7 +959,8 @@ int sqlite3CreateFunc(
|
||||
void *pUserData,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
FuncDestructor *pDestructor
|
||||
){
|
||||
FuncDef *p;
|
||||
int nName;
|
||||
@ -969,10 +988,10 @@ int sqlite3CreateFunc(
|
||||
}else if( enc==SQLITE_ANY ){
|
||||
int rc;
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
|
||||
pUserData, xFunc, xStep, xFinal);
|
||||
pUserData, xFunc, xStep, xFinal, pDestructor);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
|
||||
pUserData, xFunc, xStep, xFinal);
|
||||
pUserData, xFunc, xStep, xFinal, pDestructor);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@ -1005,6 +1024,15 @@ int sqlite3CreateFunc(
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/* If an older version of the function with a configured destructor is
|
||||
** being replaced invoke the destructor function here. */
|
||||
functionDestroy(db, p);
|
||||
|
||||
if( pDestructor ){
|
||||
pDestructor->nRef++;
|
||||
}
|
||||
p->pDestructor = pDestructor;
|
||||
p->flags = 0;
|
||||
p->xFunc = xFunc;
|
||||
p->xStep = xStep;
|
||||
@ -1019,7 +1047,7 @@ int sqlite3CreateFunc(
|
||||
*/
|
||||
int sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
@ -1029,7 +1057,39 @@ int sqlite3_create_function(
|
||||
){
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
|
||||
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, 0);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sqlite3_create_function_v2(
|
||||
sqlite3 *db,
|
||||
const char *zFunc,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xDestroy)(void *)
|
||||
){
|
||||
int rc;
|
||||
FuncDestructor *pArg = 0;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( xDestroy ){
|
||||
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
|
||||
if( !pArg ) goto out;
|
||||
pArg->xDestroy = xDestroy;
|
||||
pArg->pUserData = p;
|
||||
}
|
||||
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
|
||||
if( pArg && pArg->nRef==0 ){
|
||||
assert( rc!=SQLITE_OK );
|
||||
sqlite3DbFree(db, pArg);
|
||||
}
|
||||
|
||||
out:
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
@ -1051,7 +1111,7 @@ int sqlite3_create_function16(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
|
||||
sqlite3DbFree(db, zFunc8);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@ -1082,7 +1142,7 @@ int sqlite3_overload_function(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
|
||||
sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
|
||||
0, sqlite3InvalidFunction, 0, 0);
|
||||
0, sqlite3InvalidFunction, 0, 0, 0);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, SQLITE_OK);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
@ -3350,6 +3350,17 @@ int sqlite3_create_function16(
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
);
|
||||
int sqlite3_create_function_v2(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*)
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Text Encodings
|
||||
|
@ -600,6 +600,7 @@ typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
typedef struct ExprSpan ExprSpan;
|
||||
typedef struct FKey FKey;
|
||||
typedef struct FuncDestructor FuncDestructor;
|
||||
typedef struct FuncDef FuncDef;
|
||||
typedef struct FuncDefHash FuncDefHash;
|
||||
typedef struct IdList IdList;
|
||||
@ -956,6 +957,27 @@ struct FuncDef {
|
||||
void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */
|
||||
char *zName; /* SQL name of the function. */
|
||||
FuncDef *pHash; /* Next with a different name but the same hash */
|
||||
FuncDestructor *pDestructor; /* Reference counted destructor function */
|
||||
};
|
||||
|
||||
/*
|
||||
** This structure encapsulates a user-function destructor callback (as
|
||||
** configured using create_function_v2()) and a reference counter. When
|
||||
** create_function_v2() is called to create a function with a destructor,
|
||||
** a single object of this type is allocated. FuncDestructor.nRef is set to
|
||||
** the number of FuncDef objects created (either 1 or 3, depending on whether
|
||||
** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
|
||||
** member of each of the new FuncDef objects is set to point to the allocated
|
||||
** FuncDestructor.
|
||||
**
|
||||
** Thereafter, when one of the FuncDef objects is deleted, the reference
|
||||
** count on this object is decremented. When it reaches 0, the destructor
|
||||
** is invoked and the FuncDestructor structure freed.
|
||||
*/
|
||||
struct FuncDestructor {
|
||||
int nRef;
|
||||
void (*xDestroy)(void *);
|
||||
void *pUserData;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2921,7 +2943,9 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
|
||||
KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
|
||||
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
|
||||
FuncDestructor *pDestructor
|
||||
);
|
||||
int sqlite3ApiExit(sqlite3 *db, int);
|
||||
int sqlite3OpenTempDatabase(Parse *);
|
||||
|
||||
|
134
src/test1.c
134
src/test1.c
@ -1790,6 +1790,131 @@ static int test_create_collation_v2(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** USAGE: sqlite3_create_function_v2 DB NAME NARG ENC ?SWITCHES?
|
||||
**
|
||||
** Available switches are:
|
||||
**
|
||||
** -func SCRIPT
|
||||
** -step SCRIPT
|
||||
** -final SCRIPT
|
||||
** -destroy SCRIPT
|
||||
*/
|
||||
typedef struct CreateFunctionV2 CreateFunctionV2;
|
||||
struct CreateFunctionV2 {
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *pFunc; /* Script for function invocation */
|
||||
Tcl_Obj *pStep; /* Script for agg. step invocation */
|
||||
Tcl_Obj *pFinal; /* Script for agg. finalization invocation */
|
||||
Tcl_Obj *pDestroy; /* Destructor script */
|
||||
};
|
||||
static void cf2Func(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
|
||||
}
|
||||
static void cf2Step(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
|
||||
}
|
||||
static void cf2Final(sqlite3_context *ctx){
|
||||
}
|
||||
static void cf2Destroy(void *pUser){
|
||||
CreateFunctionV2 *p = (CreateFunctionV2 *)pUser;
|
||||
|
||||
if( p->interp && p->pDestroy ){
|
||||
int rc = Tcl_EvalObjEx(p->interp, p->pDestroy, 0);
|
||||
if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp);
|
||||
}
|
||||
|
||||
if( p->pFunc ) Tcl_DecrRefCount(p->pFunc);
|
||||
if( p->pStep ) Tcl_DecrRefCount(p->pStep);
|
||||
if( p->pFinal ) Tcl_DecrRefCount(p->pFinal);
|
||||
if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
static int test_create_function_v2(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The invoking TCL interpreter */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zFunc;
|
||||
int nArg;
|
||||
int enc;
|
||||
CreateFunctionV2 *p;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
struct EncTable {
|
||||
const char *zEnc;
|
||||
int enc;
|
||||
} aEnc[] = {
|
||||
{"utf8", SQLITE_UTF8 },
|
||||
{"utf16", SQLITE_UTF16 },
|
||||
{"utf16le", SQLITE_UTF16LE },
|
||||
{"utf16be", SQLITE_UTF16BE },
|
||||
{"any", SQLITE_ANY },
|
||||
{"0", 0 }
|
||||
};
|
||||
|
||||
if( objc<5 || (objc%2)==0 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zFunc = Tcl_GetString(objv[2]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR;
|
||||
if( Tcl_GetIndexFromObjStruct(interp, objv[4], aEnc, sizeof(aEnc[0]),
|
||||
"encoding", 0, &enc)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
enc = aEnc[enc].enc;
|
||||
|
||||
p = sqlite3_malloc(sizeof(CreateFunctionV2));
|
||||
assert( p );
|
||||
memset(p, 0, sizeof(CreateFunctionV2));
|
||||
p->interp = interp;
|
||||
|
||||
for(i=5; i<objc; i+=2){
|
||||
int iSwitch;
|
||||
const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0};
|
||||
if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){
|
||||
sqlite3_free(p);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
switch( iSwitch ){
|
||||
case 0: p->pFunc = objv[i+1]; break;
|
||||
case 1: p->pStep = objv[i+1]; break;
|
||||
case 2: p->pFinal = objv[i+1]; break;
|
||||
case 3: p->pDestroy = objv[i+1]; break;
|
||||
}
|
||||
}
|
||||
if( p->pFunc ) p->pFunc = Tcl_DuplicateObj(p->pFunc);
|
||||
if( p->pStep ) p->pStep = Tcl_DuplicateObj(p->pStep);
|
||||
if( p->pFinal ) p->pFinal = Tcl_DuplicateObj(p->pFinal);
|
||||
if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy);
|
||||
|
||||
if( p->pFunc ) Tcl_IncrRefCount(p->pFunc);
|
||||
if( p->pStep ) Tcl_IncrRefCount(p->pStep);
|
||||
if( p->pFinal ) Tcl_IncrRefCount(p->pFinal);
|
||||
if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy);
|
||||
|
||||
rc = sqlite3_create_function_v2(db, zFunc, nArg, enc, (void *)p,
|
||||
(p->pFunc ? cf2Func : 0),
|
||||
(p->pStep ? cf2Step : 0),
|
||||
(p->pFinal ? cf2Final : 0),
|
||||
cf2Destroy
|
||||
);
|
||||
if( rc!=SQLITE_OK ){
|
||||
p->interp = 0;
|
||||
cf2Destroy(p);
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
|
||||
*/
|
||||
@ -2291,7 +2416,7 @@ static int test_collate_func(
|
||||
int nB, const void *zB
|
||||
){
|
||||
Tcl_Interp *i = pTestCollateInterp;
|
||||
int encin = (int)pCtx;
|
||||
int encin = SQLITE_PTR_TO_INT(pCtx);
|
||||
int res;
|
||||
int n;
|
||||
|
||||
@ -2420,7 +2545,7 @@ static void test_collate_needed_cb(
|
||||
}
|
||||
zNeededCollation[i] = 0;
|
||||
sqlite3_create_collation(
|
||||
db, "test_collate", ENC(db), (void *)enc, test_collate_func);
|
||||
db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2469,8 +2594,8 @@ static int alignmentCollFunc(
|
||||
){
|
||||
int rc, n;
|
||||
n = nKey1<nKey2 ? nKey1 : nKey2;
|
||||
if( nKey1>0 && 1==(1&(int)pKey1) ) unaligned_string_counter++;
|
||||
if( nKey2>0 && 1==(1&(int)pKey2) ) unaligned_string_counter++;
|
||||
if( nKey1>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey1))) ) unaligned_string_counter++;
|
||||
if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++;
|
||||
rc = memcmp(pKey1, pKey2, n);
|
||||
if( rc==0 ){
|
||||
rc = nKey1 - nKey2;
|
||||
@ -5187,6 +5312,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
|
||||
|
||||
/* Functions from os.h */
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
|
71
test/func3.test
Normal file
71
test/func3.test
Normal file
@ -0,0 +1,71 @@
|
||||
# 2010 August 27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that destructor functions associated
|
||||
# with functions created using sqlite3_create_function_v2() is
|
||||
# correctly invoked.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
do_test func3-1.1 {
|
||||
set destroyed 0
|
||||
proc destroy {} { set ::destroyed 1 }
|
||||
sqlite3_create_function_v2 db f2 -1 any -func f2 -destroy destroy
|
||||
set destroyed
|
||||
} 0
|
||||
do_test func3-1.2 {
|
||||
sqlite3_create_function_v2 db f2 -1 utf8 -func f2
|
||||
set destroyed
|
||||
} 0
|
||||
do_test func3-1.3 {
|
||||
sqlite3_create_function_v2 db f2 -1 utf16le -func f2
|
||||
set destroyed
|
||||
} 0
|
||||
do_test func3-1.4 {
|
||||
sqlite3_create_function_v2 db f2 -1 utf16be -func f2
|
||||
set destroyed
|
||||
} 1
|
||||
|
||||
do_test func3-2.1 {
|
||||
set destroyed 0
|
||||
proc destroy {} { set ::destroyed 1 }
|
||||
sqlite3_create_function_v2 db f3 -1 utf8 -func f3 -destroy destroy
|
||||
set destroyed
|
||||
} 0
|
||||
do_test func3-2.2 {
|
||||
sqlite3_create_function_v2 db f3 -1 utf8 -func f3
|
||||
set destroyed
|
||||
} 1
|
||||
|
||||
do_test func3-3.1 {
|
||||
set destroyed 0
|
||||
proc destroy {} { set ::destroyed 1 }
|
||||
sqlite3_create_function_v2 db f3 -1 any -func f3 -destroy destroy
|
||||
set destroyed
|
||||
} 0
|
||||
do_test func3-3.2 {
|
||||
db close
|
||||
set destroyed
|
||||
} 1
|
||||
|
||||
sqlite3 db test.db
|
||||
do_test func3-4.1 {
|
||||
set destroyed 0
|
||||
set rc [catch {
|
||||
sqlite3_create_function_v2 db f3 -1 any -func f3 -step f3 -destroy destroy
|
||||
} msg]
|
||||
list $rc $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
do_test func3-4.2 { set destroyed } 0
|
||||
|
||||
finish_test
|
Loading…
Reference in New Issue
Block a user