1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Add support for the sqlite3_get_clientdata() and sqlite3_set_clientdata()

interfaces, to better support JNI.

FossilOrigin-Name: 9806c0dd2802d68b67c25c4f3347ed532f9a98b051e775d34e9182dd2f099891
This commit is contained in:
drh
2023-09-11 14:55:05 +00:00
6 changed files with 200 additions and 97 deletions

View File

@ -447,8 +447,7 @@ struct S3JniDb {
#ifdef SQLITE_ENABLE_FTS5 #ifdef SQLITE_ENABLE_FTS5
jobject jFtsApi /* global ref to s3jni_fts5_api_from_db() */; jobject jFtsApi /* global ref to s3jni_fts5_api_from_db() */;
#endif #endif
S3JniDb * pNext /* Next entry in SJG.perDb.aFree or SJG.perDb.aHead */; S3JniDb * pNext /* Next entry in SJG.perDb.aFree */;
S3JniDb * pPrev /* Previous entry in SJG.perDb.aFree or SJG.perDb.aHead */;
}; };
/* /*
@ -579,7 +578,6 @@ struct S3JniGlobalType {
** client-defined state to db handles there. ** client-defined state to db handles there.
*/ */
struct { struct {
S3JniDb * aHead /* Linked list of in-use instances */;
S3JniDb * aFree /* Linked list of free instances */; S3JniDb * aFree /* Linked list of free instances */;
sqlite3_mutex * mutex /* mutex for aHead and aFree */; sqlite3_mutex * mutex /* mutex for aHead and aFree */;
void const * locker /* perDb mutex is held on this object's void const * locker /* perDb mutex is held on this object's
@ -1225,20 +1223,10 @@ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
*/ */
static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){ static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
assert( s ); assert( s );
S3JniMutex_S3JniDb_assertLocker;
if( s ){ if( s ){
S3JniMutex_S3JniDb_assertLocker;
assert(s->pPrev != s);
assert(s->pNext != s);
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
if(s->pNext) s->pNext->pPrev = s->pPrev;
if(s->pPrev) s->pPrev->pNext = s->pNext;
else if(SJG.perDb.aHead == s){
assert(!s->pPrev);
SJG.perDb.aHead = s->pNext;
}
S3JniDb_clear(env, s); S3JniDb_clear(env, s);
s->pNext = SJG.perDb.aFree; s->pNext = SJG.perDb.aFree;
if(s->pNext) s->pNext->pPrev = s;
SJG.perDb.aFree = s; SJG.perDb.aFree = s;
} }
} }
@ -1448,40 +1436,27 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){
if( SJG.perDb.aFree ){ if( SJG.perDb.aFree ){
rv = SJG.perDb.aFree; rv = SJG.perDb.aFree;
SJG.perDb.aFree = rv->pNext; SJG.perDb.aFree = rv->pNext;
assert(rv->pNext != rv); rv->pNext = 0;
assert(!rv->pPrev);
if( rv->pNext ){
assert(rv->pNext->pPrev == rv);
rv->pNext->pPrev = 0;
rv->pNext = 0;
}
s3jni_incr( &SJG.metrics.nPdbRecycled ); s3jni_incr( &SJG.metrics.nPdbRecycled );
}else{ }else{
rv = s3jni_malloc( sizeof(S3JniDb)); rv = s3jni_malloc( sizeof(S3JniDb));
if( rv ){ if( rv ){
memset(rv, 0, sizeof(S3JniDb));
s3jni_incr( &SJG.metrics.nPdbAlloc ); s3jni_incr( &SJG.metrics.nPdbAlloc );
} }
} }
if( rv ){ if( rv ){
rv->pNext = SJG.perDb.aHead; memset(rv, 0, sizeof(S3JniDb));
SJG.perDb.aHead = rv;
if( rv->pNext ){
assert(!rv->pNext->pPrev);
rv->pNext->pPrev = rv;
}
rv->jDb = S3JniRefGlobal(jDb); rv->jDb = S3JniRefGlobal(jDb);
} }
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
return rv; return rv;
} }
#define S3JniDb_clientdata_key "S3JniDb"
/* Short-lived code consolidator. */ /* Short-lived code consolidator. */
#define S3JniDb_search \ #define S3JniDb_search \
s = SJG.perDb.aHead; \ s = pDb ? sqlite3_get_clientdata(pDb, S3JniDb_clientdata_key) : 0
for( ; pDb && s; s = s->pNext){ \
if( s->pDb == pDb ) break; \
}
/* /*
** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3 ** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3
@ -1511,10 +1486,20 @@ static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
if( jDb ) pDb = PtrGet_sqlite3(jDb); if( jDb ) pDb = PtrGet_sqlite3(jDb);
S3JniDb_search; S3JniDb_search;
return s; return s;
} }
#define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB)) #define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB))
/*
** S3JniDb finalizer for use with sqlite3_set_clientdata().
*/
static void S3JniDb_xDestroy(void *p){
S3JniDb * ps = p;
S3JniDeclLocal_env;
assert( !ps->pNext );
S3JniDb_set_aside(ps);
}
/* /*
** Returns the S3JniDb object for the sqlite3 object, or NULL if pDb ** Returns the S3JniDb object for the sqlite3 object, or NULL if pDb
** is NULL, or no matching entry ** is NULL, or no matching entry
@ -2132,9 +2117,15 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
jc->pdbOpening = 0; jc->pdbOpening = 0;
assert( !ps->pDb && "it's still being opened" ); assert( !ps->pDb && "it's still being opened" );
assert( ps->jDb ); assert( ps->jDb );
ps->pDb = pDb; rc = sqlite3_set_clientdata(pDb, S3JniDb_clientdata_key,
ps, 0/* we'll re-set this after open()
completes. */);
if( rc ){
return rc;
}
NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb) NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb)
/* As of here, the Java/C connection is complete */; /* As of here, the Java/C connection is complete */;
ps->pDb = pDb;
for( i = 0; go && 0==rc; ++i ){ for( i = 0; go && 0==rc; ++i ){
S3JniAutoExtension ax = {0,0} S3JniAutoExtension ax = {0,0}
/* We need a copy of the auto-extension object, with our own /* We need a copy of the auto-extension object, with our own
@ -2447,8 +2438,6 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
/* Wrapper for sqlite3_close(_v2)(). */ /* Wrapper for sqlite3_close(_v2)(). */
static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
int rc = 0; int rc = 0;
//#define CLOSE_DB_LOCKED /* An experiment */
#ifndef CLOSE_DB_LOCKED
S3JniDb * const ps = S3JniDb_from_java(jDb); S3JniDb * const ps = S3JniDb_from_java(jDb);
assert(version == 1 || version == 2); assert(version == 1 || version == 2);
@ -2458,38 +2447,8 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
: (jint)sqlite3_close_v2(ps->pDb); : (jint)sqlite3_close_v2(ps->pDb);
if( 0==rc ){ if( 0==rc ){
NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0); NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
S3JniDb_set_aside(ps)
/* MUST come after close() because of ps->trace. */;
} }
} }
#else
/* This impl leads to an assertion in sqlite3_close[_v2]()
pthreadMutexEnter: Assertion `p->id==SQLITE_MUTEX_RECURSIVE
|| pthreadMutexNotheld(p)' failed.
For reasons not yet fully understood.
*/
assert(version == 1 || version == 2);
if( 0!=jDb ){
S3JniDb * ps;
S3JniMutex_S3JniDb_enter;
ps = S3JniDb_from_java_unlocked(jDb);
if( ps && ps->pDb ){
rc = 1==version
? (jint)sqlite3_close(ps->pDb)
: (jint)sqlite3_close_v2(ps->pDb);
if( 0==rc ){
S3JniDb_set_aside_unlocked(ps)
/* MUST come after close() because of ps->hooks.trace. */;
NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
}
}else{
/* ps is from S3Global.perDb.aFree. */
}
S3JniMutex_S3JniDb_leave;
}
#endif
return (jint)rc; return (jint)rc;
} }
@ -3307,23 +3266,26 @@ end:
static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc, static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc,
S3JniDb * ps, sqlite3 **ppDb, S3JniDb * ps, sqlite3 **ppDb,
jobject jOut, int theRc){ jobject jOut, int theRc){
int rc = 0;
jc->pdbOpening = 0; jc->pdbOpening = 0;
if( *ppDb ){ if( *ppDb ){
assert(ps->jDb); assert(ps->jDb);
if( 0==ps->pDb ){ if( 0==ps->pDb ){
ps->pDb = *ppDb; ps->pDb = *ppDb;
NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb) NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb);
/* As of here, the Java/C connection is complete */;
}else{ }else{
assert( ps->pDb==*ppDb assert( ps->pDb==*ppDb
&& "Set up via s3jni_run_java_auto_extensions()" ); && "Set up via s3jni_run_java_auto_extensions()" );
} }
rc = sqlite3_set_clientdata(ps->pDb, S3JniDb_clientdata_key,
ps, S3JniDb_xDestroy);
/* As of here, the Java/C connection is complete */
}else{ }else{
S3JniDb_set_aside(ps); S3JniDb_set_aside(ps);
ps = 0; ps = 0;
} }
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0); OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
return theRc; return theRc ? theRc : rc;
} }
S3JniApi(sqlite3_open(),jint,1open)( S3JniApi(sqlite3_open(),jint,1open)(
@ -4040,7 +4002,6 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
while( S3JniGlobal.perDb.aFree ){ while( S3JniGlobal.perDb.aFree ){
S3JniDb * const d = S3JniGlobal.perDb.aFree; S3JniDb * const d = S3JniGlobal.perDb.aFree;
S3JniGlobal.perDb.aFree = d->pNext; S3JniGlobal.perDb.aFree = d->pNext;
d->pNext = 0;
S3JniDb_clear(env, d); S3JniDb_clear(env, d);
sqlite3_free(d); sqlite3_free(d);
} }

View File

@ -1,5 +1,5 @@
C Remove\sout-of-date\scomment\sregarding\suse\sof\sParse.pConstExpr. C Add\ssupport\sfor\sthe\ssqlite3_get_clientdata()\sand\ssqlite3_set_clientdata()\ninterfaces,\sto\sbetter\ssupport\sJNI.
D 2023-09-09T17:53:55.931 D 2023-09-11T14:55:05.474
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -238,7 +238,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551 F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9 F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c 3d80af6bfa4af38dc50a919f97219a481410de1f6f885644b2f97cd64ab9b863 F ext/jni/src/c/sqlite3-jni.c aaec2851258a7d9c9907d8e864a17e055676ec0adb64f335d979fa19674a0cab
F ext/jni/src/c/sqlite3-jni.h 12e1a5ef5ee1795dc22577c285b4518dfd8aa4af45757f6cb81a555d967bf201 F ext/jni/src/c/sqlite3-jni.h 12e1a5ef5ee1795dc22577c285b4518dfd8aa4af45757f6cb81a555d967bf201
F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436 F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4 F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
@ -669,7 +669,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c 51141f1c09ccb177057e5813e6302a5e32e5ba88cc4a756318a35081010fc6df F src/json.c 51141f1c09ccb177057e5813e6302a5e32e5ba88cc4a756318a35081010fc6df
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0 F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
F src/main.c 58a3150ba371da9ddac8229a39be5e8bb2c15ac46d1f908cd55596cf825c6fbc F src/main.c 3a6f64cb47c605aa8b85de90474f448fc69366cd93ccf46a1276f5ec44c4a110
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23 F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@ -708,10 +708,10 @@ F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c e9fb48546ab1882639a3a960383f6342dddb776c0227615f8e19de51f0102f68 F src/select.c e9fb48546ab1882639a3a960383f6342dddb776c0227615f8e19de51f0102f68
F src/shell.c.in 2f9be25294b68b07e7e81f0adcec4475aba6011b64f160e414efe226910c4d7b F src/shell.c.in 2f9be25294b68b07e7e81f0adcec4475aba6011b64f160e414efe226910c4d7b
F src/sqlite.h.in 1b9be583d9011b9fe09fbdcc33cce19a1d2b40d84ebd164836420a6d256f2fb1 F src/sqlite.h.in 931a58d119d5cf87110648f39fa0bb9f1738b0068cb68250d893304a471bd6c0
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
F src/sqliteInt.h 304deb0cb33993a19545809d245a2bfd34afb77ae701087597f64c463de596cc F src/sqliteInt.h 0c33d256c0f7de824c7cef1aef14b66c94e4f0de77d598284048e73be6bb4f39
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -2117,8 +2117,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 6357491bd1b97f7abddf1a83860f3763cd870033bddc74bd9994a6440fe8c762 P 71548f72ad578db3d6ee409956386ace23ab2258d37cdc29ef2fb126e48f1ee3 7b884832b71c23e62ba3c0d53f7c89199734c351f909d84ac19ac18c7ddccbd8
R 8a752dcf4f4102597c3c43c05826b63b R ed133595420eb79056e6b2e7f8f7826c
U dan T +closed 7b884832b71c23e62ba3c0d53f7c89199734c351f909d84ac19ac18c7ddccbd8
Z 12968dd6d6930c9a75018f43087e8626 U drh
Z 4388a2fb0fa820775dbaf90786b95f10
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
71548f72ad578db3d6ee409956386ace23ab2258d37cdc29ef2fb126e48f1ee3 9806c0dd2802d68b67c25c4f3347ed532f9a98b051e775d34e9182dd2f099891

View File

@ -1253,6 +1253,14 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
} }
#endif #endif
while( db->pDbData ){
DbClientData *p = db->pDbData;
db->pDbData = p->pNext;
assert( p->pData!=0 );
if( p->xDestructor ) p->xDestructor(p->pData);
sqlite3_free(p);
}
/* Convert the connection into a zombie and then close it. /* Convert the connection into a zombie and then close it.
*/ */
db->eOpenState = SQLITE_STATE_ZOMBIE; db->eOpenState = SQLITE_STATE_ZOMBIE;
@ -3710,6 +3718,69 @@ int sqlite3_collation_needed16(
} }
#endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_UTF16 */
/*
** Find existing client data.
*/
void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
DbClientData *p;
sqlite3_mutex_enter(db->mutex);
for(p=db->pDbData; p; p=p->pNext){
if( strcmp(p->zName, zName)==0 ){
void *pResult = p->pData;
sqlite3_mutex_leave(db->mutex);
return pResult;
}
}
sqlite3_mutex_leave(db->mutex);
return 0;
}
/*
** Add new client data to a database connection.
*/
int sqlite3_set_clientdata(
sqlite3 *db, /* Attach client data to this connection */
const char *zName, /* Name of the client data */
void *pData, /* The client data itself */
void (*xDestructor)(void*) /* Destructor */
){
DbClientData *p, **pp;
sqlite3_mutex_enter(db->mutex);
pp = &db->pDbData;
for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
pp = &p->pNext;
}
if( p ){
assert( p->pData!=0 );
if( p->xDestructor ) p->xDestructor(p->pData);
if( pData==0 ){
*pp = p->pNext;
sqlite3_free(p);
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
}else if( pData==0 ){
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}else{
size_t n = strlen(zName);
p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
if( p==0 ){
if( xDestructor ) xDestructor(pData);
sqlite3_mutex_leave(db->mutex);
return SQLITE_NOMEM;
}
memcpy(p->zName, zName, n+1);
p->pNext = db->pDbData;
db->pDbData = p;
}
p->pData = pData;
p->xDestructor = xDestructor;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_DEPRECATED #ifndef SQLITE_OMIT_DEPRECATED
/* /*
** This function is now an anachronism. It used to be used to recover from a ** This function is now an anachronism. It used to be used to recover from a

View File

@ -5325,6 +5325,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt);
*/ */
int sqlite3_reset(sqlite3_stmt *pStmt); int sqlite3_reset(sqlite3_stmt *pStmt);
/* /*
** CAPI3REF: Create Or Redefine SQL Functions ** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines} ** KEYWORDS: {function creation routines}
@ -5879,32 +5880,32 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** METHOD: sqlite3_context ** METHOD: sqlite3_context
** **
** These functions may be used by (non-aggregate) SQL functions to ** These functions may be used by (non-aggregate) SQL functions to
** associate metadata with argument values. If the same value is passed to ** associate auxiliary data with argument values. If the same argument
** multiple invocations of the same SQL function during query execution, under ** value is passed to multiple invocations of the same SQL function during
** some circumstances the associated metadata may be preserved. An example ** query execution, under some circumstances the associated auxiliary data
** of where this might be useful is in a regular-expression matching ** might be preserved. An example of where this might be useful is in a
** function. The compiled version of the regular expression can be stored as ** regular-expression matching function. The compiled version of the regular
** metadata associated with the pattern string. ** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same, ** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple ** the compiled regular expression can be reused on multiple
** invocations of the same function. ** invocations of the same function.
** **
** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata ** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument ** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most ** value to the application-defined function. ^N is zero for the left-most
** function argument. ^If there is no metadata ** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer. ** returns a NULL pointer.
** **
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
** argument of the application-defined function. ^Subsequent ** N-th argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent
** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or ** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
** NULL if the metadata has been discarded. ** NULL if the auxiliary data has been discarded.
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly ** SQLite will invoke the destructor function X with parameter P exactly
** once, when the metadata is discarded. ** once, when the auxiliary data is discarded.
** SQLite is free to discard the metadata at any time, including: <ul> ** SQLite is free to discard the auxiliary data at any time, including: <ul>
** <li> ^(when the corresponding function parameter changes)^, or ** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
** SQL statement)^, or ** SQL statement)^, or
@ -5920,7 +5921,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** function implementation should not make any use of P after ** function implementation should not make any use of P after
** sqlite3_set_auxdata() has been called. ** sqlite3_set_auxdata() has been called.
** **
** ^(In practice, metadata is preserved between function calls for ** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal ** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^ ** values and [parameters] and expressions composed from the same.)^
** **
@ -5930,10 +5931,67 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** **
** These routines must be called from the same thread in which ** These routines must be called from the same thread in which
** the SQL function is running. ** the SQL function is running.
**
** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()].
*/ */
void *sqlite3_get_auxdata(sqlite3_context*, int N); void *sqlite3_get_auxdata(sqlite3_context*, int N);
void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
** CAPI3REF: Database Connection Client Data
** METHOD: sqlite3
**
** These functions are used to associate one or more named pointers
** with a [database connection].
** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P
** to be attached to [database connection] D using name N. Subsequent
** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P
** or a NULL pointer if there were no prior calls to
** sqlite3_set_clientdata() with the same values of D and N.
** Names are compared using strcmp() and are thus case sensitive.
**
** If P and X are both non-NULL, then the destructor X is invoked with
** argument P on the first of the following occurrences:
** <ul>
** <li> An out-of-memory error occurs during the call to
** sqlite3_set_clientdata() which attempts to register pointer P.
** <li> A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made
** with the same D and N parameters.
** <li> The database connection closes. SQLite does not make any guarantees
** about the order in which destructors are called, only that all
** destructors will be called exactly once at some point during the
** database connection closingi process.
** </ul>
**
** SQLite does not do anything with client data other than invoke
** destructors on the client data at the appropriate time. The intended
** use for client data is to provide a mechanism for wrapper libraries
** to store additional information about an SQLite database connection.
**
** There is no limit (other than available memory) on the number of different
** client data pointers (with different names) that can be attached to a
** single database connection. However, the implementation is optimized
** for the case of having only one or two different client data names.
** Applications and wrapper libraries are discouraged from using more than
** one client data name each.
**
** There is no way to enumerate the client data pointers
** associated with a database connection. The N parameter can be thought
** of as a secret key such that only code that knows the secret key is able
** to access the associated data.
**
** Security Warning: These interfaces should not be exposed in scripting
** languages or in other circumstances where it might be possible for an
** an attacker to invoke them. Any agent that can invoke these interfaces
** can probably also take control of the process.
**
** Database connection client data is only available for SQLite
** version 3.44.0 ([dateof:3.44.0]) and later.
**
** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()].
*/
void *sqlite3_get_clientdata(sqlite3*,const char*);
int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
/* /*
** CAPI3REF: Constants Defining Special Destructor Behavior ** CAPI3REF: Constants Defining Special Destructor Behavior

View File

@ -1273,6 +1273,7 @@ typedef struct Column Column;
typedef struct Cte Cte; typedef struct Cte Cte;
typedef struct CteUse CteUse; typedef struct CteUse CteUse;
typedef struct Db Db; typedef struct Db Db;
typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer; typedef struct DbFixer DbFixer;
typedef struct Schema Schema; typedef struct Schema Schema;
typedef struct Expr Expr; typedef struct Expr Expr;
@ -1751,6 +1752,7 @@ struct sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */ i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
DbClientData *pDbData; /* sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN /* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@ -4358,6 +4360,16 @@ struct CteUse {
}; };
/* Client data associated with sqlite3_set_clientdata() and
** sqlite3_get_clientdata().
*/
struct DbClientData {
DbClientData *pNext; /* Next in a linked list */
void *pData; /* The data */
void (*xDestructor)(void*); /* Destructor. Might be NULL */
char zName[1]; /* Name of this client data. MUST BE LAST */
};
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
/* /*
** An instance of the TreeView object is used for printing the content of ** An instance of the TreeView object is used for printing the content of