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

Make JNI sqlite3_trace_v2() thread-safe. Re-add a piece removed in [bae4d022aad9b] to work around a JVM crash which is unpredictably triggered by its substitute. Fix the THREADMODE=0 JNI build. Further internal API simplifications.

FossilOrigin-Name: 3f9f7a9cb08b0687ad206605a5109306762df9ae8bdeab2d8d60bf9373c9ad32
This commit is contained in:
stephan
2023-08-27 10:40:00 +00:00
parent 32a79760b5
commit 95f5d85d4a
5 changed files with 115 additions and 90 deletions

View File

@ -297,9 +297,12 @@ tests: tester
######################################################################## ########################################################################
# Build each SQLITE_THREADMODE variant and run all tests against them. # Build each SQLITE_THREADMODE variant and run all tests against them.
multitest: clean multitest: clean
$(MAKE) opt.threadsafe=0 tests clean $(MAKE) opt.threadsafe=0 opt.oom=1 tests clean
$(MAKE) opt.threadsafe=1 tests clean $(MAKE) opt.threadsafe=0 opt.oom=0 tests clean
$(MAKE) opt.threadsafe=2 tests clean $(MAKE) opt.threadsafe=1 opt.oom=1 tests clean
$(MAKE) opt.threadsafe=1 opt.oom=0 tests clean
$(MAKE) opt.threadsafe=2 opt.oom=1 tests clean
$(MAKE) opt.threadsafe=2 opt.oom=0 tests clean
######################################################################## ########################################################################

View File

@ -404,9 +404,8 @@ struct S3JniHook{
/* We lookup the jObj.xDestroy() method as-needed for contexts which /* We lookup the jObj.xDestroy() method as-needed for contexts which
** have custom finalizers. */ ** have custom finalizers. */
}; };
#if !defined(SQLITE_ENABLE_PREUPDATE_HOOK) || defined(SQLITE_ENABLE_SQLLOG) /* For clean bitwise-copy init of local instances. */
static const S3JniHook S3JniHook_empty = {0,0}; static const S3JniHook S3JniHook_empty = {0,0};
#endif
/* /*
** Per-(sqlite3*) state for various JNI bindings. This state is ** Per-(sqlite3*) state for various JNI bindings. This state is
@ -456,10 +455,10 @@ struct S3JniEnv {
JNIEnv *env /* env in which this cache entry was created */; JNIEnv *env /* env in which this cache entry was created */;
/* /*
** pdbOpening is used to coordinate the Java/DB connection of a ** pdbOpening is used to coordinate the Java/DB connection of a
** being-open()'d db in the face of auto-extensions. "The problem" ** being-open()'d db in the face of auto-extensions.
** is that auto-extensions run before we can bind the C db to its ** Auto-extensions run before we can bind the C db to its Java
** Java representation, but auto-extensions require that binding. We ** representation, but auto-extensions require that binding to pass
** handle this as follows: ** on to their Java-side callbacks. We handle this as follows:
** **
** - In the JNI side of sqlite3_open(), allocate the Java side of ** - In the JNI side of sqlite3_open(), allocate the Java side of
** that connection and set pdbOpening to point to that ** that connection and set pdbOpening to point to that
@ -497,8 +496,8 @@ enum UDFType {
UDF_WINDOW UDF_WINDOW
}; };
/** /*
State for binding Java-side UDFs. ** State for binding Java-side UDFs.
*/ */
typedef struct S3JniUdf S3JniUdf; typedef struct S3JniUdf S3JniUdf;
struct S3JniUdf { struct S3JniUdf {
@ -506,11 +505,11 @@ struct S3JniUdf {
char * zFuncName /* Only for error reporting and debug logging */; char * zFuncName /* Only for error reporting and debug logging */;
enum UDFType type; enum UDFType type;
/** Method IDs for the various UDF methods. */ /** Method IDs for the various UDF methods. */
jmethodID jmidxFunc /* Java ID of xFunc method */; jmethodID jmidxFunc /* xFunc method */;
jmethodID jmidxStep /* Java ID of xStep method */; jmethodID jmidxStep /* xStep method */;
jmethodID jmidxFinal /* Java ID of xFinal method */; jmethodID jmidxFinal /* xFinal method */;
jmethodID jmidxValue /* Java ID of xValue method */; jmethodID jmidxValue /* xValue method */;
jmethodID jmidxInverse /* Java ID of xInverse method */; jmethodID jmidxInverse /* xInverse method */;
S3JniUdf * pNext /* Next entry in SJG.udf.aFree. */; S3JniUdf * pNext /* Next entry in SJG.udf.aFree. */;
}; };
@ -592,6 +591,7 @@ struct S3JniGlobalType {
** and never released. ** and never released.
*/ */
struct { struct {
jclass cObj /* global ref to java.lang.Object */;
jclass cLong /* global ref to java.lang.Long */; jclass cLong /* global ref to java.lang.Long */;
jclass cString /* global ref to java.lang.String */; jclass cString /* global ref to java.lang.String */;
jobject oCharsetUtf8 /* global ref to StandardCharset.UTF_8 */; jobject oCharsetUtf8 /* global ref to StandardCharset.UTF_8 */;
@ -729,10 +729,10 @@ static void s3jni_incr( volatile unsigned int * const p ){
SJG.autoExt.locker = env; \ SJG.autoExt.locker = env; \
s3jni_incr( &SJG.metrics.nMutexAutoExt ) s3jni_incr( &SJG.metrics.nMutexAutoExt )
#define S3JniMutex_Ext_leave \ #define S3JniMutex_Ext_leave \
assert( env == SJG.autoExt.locker ); \ assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ); \
sqlite3_mutex_leave( SJG.autoExt.mutex ) sqlite3_mutex_leave( SJG.autoExt.mutex )
#define S3JniMutex_Ext_assertLocker \ #define S3JniMutex_Ext_assertLocker \
assert( env == SJG.autoExt.locker ) assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" )
#define S3JniMutex_Global_enter \ #define S3JniMutex_Global_enter \
sqlite3_mutex_enter( SJG.mutex ); \ sqlite3_mutex_enter( SJG.mutex ); \
@ -775,6 +775,7 @@ static void s3jni_incr( volatile unsigned int * const p ){
#define S3JniMutex_Global_leave #define S3JniMutex_Global_leave
#define S3JniMutex_Nph_enter #define S3JniMutex_Nph_enter
#define S3JniMutex_Nph_leave #define S3JniMutex_Nph_leave
#define S3JniMutex_S3JniDb_assertLocker
#define S3JniMutex_S3JniDb_enter #define S3JniMutex_S3JniDb_enter
#define S3JniMutex_S3JniDb_leave #define S3JniMutex_S3JniDb_leave
#endif #endif
@ -1090,8 +1091,8 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj){
** cleared. It is legal to call this when the object has no Java ** cleared. It is legal to call this when the object has no Java
** references. ** references.
*/ */
static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, static void S3JniHook_unref_impl(JNIEnv * const env, S3JniHook * const s,
int doXDestroy){ int doXDestroy){
if( s->jObj ){ if( s->jObj ){
if( doXDestroy ){ if( doXDestroy ){
s3jni_call_xDestroy(env, s->jObj); s3jni_call_xDestroy(env, s->jObj);
@ -1100,17 +1101,20 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s,
} }
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
} }
#define S3JniHook_unref(H,X) S3JniHook_unref_impl(env, (H), (X))
/* /*
** Internal helper for many hook callback impls. Locks the S3JniDb ** Internal helper for many hook callback impls. Locks the S3JniDb
** mutex, makes a copy of src into dest, with one change: if src->jObj ** mutex, makes a copy of src into dest, with one change: if src->jObj
** is not NULL then dest->jObj will be a new LOCAL ref to src->jObj ** is not NULL then dest->jObj will be a new LOCAL ref to src->jObj
** instead of a copy of the prior GLOBAL ref. Then it unlocks the ** instead of a copy of the prior GLOBAL ref. Then it unlocks the
** mutex. If dest->jObj is not NULL when this returns then the caller ** mutex.
** is obligated to eventually free the new ref by passing dest->jObj **
** to S3JniUnrefLocal(). The dest pointer must NOT be passed to ** If dest->jObj is not NULL when this returns then the caller is
** S3JniHook_unref(), as that one assumes that dest->jObj is a GLOBAL ** obligated to eventually free the new ref by passing *dest to
** ref (it's illegal to try to unref the wrong ref type).. ** S3JniHook_localundup(). The dest pointer must NOT be passed to
** S3JniHook_unref(), as that routine assumes that dest->jObj is a
** GLOBAL ref (it's illegal to try to unref the wrong ref type)..
** **
** Background: when running a hook we need a call-local copy lest ** Background: when running a hook we need a call-local copy lest
** another thread modify the hook while we're running it. That copy ** another thread modify the hook while we're running it. That copy
@ -1123,6 +1127,7 @@ static void S3JniHook_localdup( JNIEnv * const env, S3JniHook const * const src,
if(dest->jObj) dest->jObj = S3JniRefLocal(dest->jObj); if(dest->jObj) dest->jObj = S3JniRefLocal(dest->jObj);
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
} }
#define S3JniHook_localundup(HOOK) S3JniUnrefLocal(HOOK.jObj)
/* /*
** Clears all of s's state. Requires that that the caller has locked ** Clears all of s's state. Requires that that the caller has locked
@ -1132,7 +1137,7 @@ static void S3JniHook_localdup( JNIEnv * const env, S3JniHook const * const src,
static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
S3JniMutex_S3JniDb_assertLocker; S3JniMutex_S3JniDb_assertLocker;
sqlite3_free( s->zMainDbName ); sqlite3_free( s->zMainDbName );
#define UNHOOK(MEMBER) S3JniHook_unref(env, &s->hooks.MEMBER, 0) #define UNHOOK(MEMBER) S3JniHook_unref(&s->hooks.MEMBER, 0)
UNHOOK(auth); UNHOOK(auth);
UNHOOK(busyHandler); UNHOOK(busyHandler);
UNHOOK(collation); UNHOOK(collation);
@ -1380,7 +1385,7 @@ static S3JniDb * S3JniDb_get(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out ** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out
** AX. ** AX.
*/ */
#define S3JniAutoExtension_clear(AX) S3JniHook_unref(env, AX, 0); #define S3JniAutoExtension_clear(AX) S3JniHook_unref(AX, 0);
/* /*
** Initializes a pre-allocated S3JniAutoExtension object. Returns ** Initializes a pre-allocated S3JniAutoExtension object. Returns
@ -1561,7 +1566,7 @@ static int CollationState_xCompare(void *pArg, int nLhs, const void *lhs,
S3JniExceptionIgnore; S3JniExceptionIgnore;
S3JniUnrefLocal(jbaLhs); S3JniUnrefLocal(jbaLhs);
S3JniUnrefLocal(jbaRhs); S3JniUnrefLocal(jbaRhs);
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
return (int)rc; return (int)rc;
} }
@ -1572,7 +1577,7 @@ static void CollationState_xDestroy(void *pArg){
S3JniDeclLocal_env; S3JniDeclLocal_env;
S3JniMutex_S3JniDb_enter; S3JniMutex_S3JniDb_enter;
S3JniHook_unref( env, &ps->hooks.collation, 1 ); S3JniHook_unref(&ps->hooks.collation, 1);
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
} }
@ -1750,12 +1755,14 @@ static int udf_args(JNIEnv *env,
jobjectArray ja = 0; jobjectArray ja = 0;
jobject jcx = new_sqlite3_context_wrapper(env, cx); jobject jcx = new_sqlite3_context_wrapper(env, cx);
jint i; jint i;
S3JniNphClass * const pNC =
S3JniGlobal_nph(env, &S3NphRefs.sqlite3_value);
*jCx = 0; *jCx = 0;
*jArgv = 0; *jArgv = 0;
if( !jcx ) goto error_oom; if( !jcx ) goto error_oom;
ja = (*env)->NewObjectArray(env, argc, pNC->klazz, NULL); ja = (*env)->NewObjectArray(
env, argc, SJG.g.cObj
/* S3JniGlobal_nph(env,&S3NphRefs.sqlite3_value)->klazz would be
more correct, but it unpredictably triggers an assert in the
JVM. */, NULL);
s3jni_oom_check( ja ); s3jni_oom_check( ja );
if( !ja ) goto error_oom; if( !ja ) goto error_oom;
for(i = 0; i < argc; ++i){ for(i = 0; i < argc; ++i){
@ -2240,7 +2247,7 @@ static int s3jni_busy_handler(void* pState, int n){
rc = s3jni_db_exception(env, ps, SQLITE_ERROR, rc = s3jni_db_exception(env, ps, SQLITE_ERROR,
"sqlite3_busy_handler() callback threw."); "sqlite3_busy_handler() callback threw.");
} }
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
return rc; return rc;
} }
@ -2260,17 +2267,17 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
return 0; return 0;
} }
jclass klazz; jclass klazz;
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
pHook->jObj = S3JniRefGlobal(jBusy); pHook->jObj = S3JniRefGlobal(jBusy);
klazz = (*env)->GetObjectClass(env, jBusy); klazz = (*env)->GetObjectClass(env, jBusy);
pHook->midCallback = (*env)->GetMethodID(env, klazz, "call", "(I)I"); pHook->midCallback = (*env)->GetMethodID(env, klazz, "call", "(I)I");
S3JniUnrefLocal(klazz); S3JniUnrefLocal(klazz);
S3JniIfThrew { S3JniIfThrew {
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
}else{ }else{
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
} }
if( 0==rc ){ if( 0==rc ){
rc = jBusy rc = jBusy
@ -2288,7 +2295,7 @@ S3JniApi(sqlite3_busy_timeout(),jint,1busy_1timeout)(
int rc = SQLITE_MISUSE; int rc = SQLITE_MISUSE;
if( ps ){ if( ps ){
S3JniMutex_S3JniDb_enter; S3JniMutex_S3JniDb_enter;
S3JniHook_unref(env, &ps->hooks.busyHandler, 0); S3JniHook_unref(&ps->hooks.busyHandler, 0);
rc = sqlite3_busy_timeout(ps->pDb, (int)ms); rc = sqlite3_busy_timeout(ps->pDb, (int)ms);
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
} }
@ -2387,7 +2394,7 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
} }
S3JniUnrefLocal(jName); S3JniUnrefLocal(jName);
} }
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
} }
@ -2404,7 +2411,7 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
(*env)->IsSameObject(env, pHook->jObj, jHook) ){ (*env)->IsSameObject(env, pHook->jObj, jHook) ){
/* no-op */ /* no-op */
}else if( !jHook ){ }else if( !jHook ){
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
sqlite3_collation_needed(ps->pDb, 0, 0); sqlite3_collation_needed(ps->pDb, 0, 0);
}else{ }else{
jclass const klazz = (*env)->GetObjectClass(env, jHook); jclass const klazz = (*env)->GetObjectClass(env, jHook);
@ -2420,7 +2427,7 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
rc = sqlite3_collation_needed16(ps->pDb, ps, s3jni_collation_needed_impl16); rc = sqlite3_collation_needed16(ps->pDb, ps, s3jni_collation_needed_impl16);
if( rc ){ if( rc ){
}else{ }else{
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
pHook->midCallback = xCallback; pHook->midCallback = xCallback;
pHook->jObj = S3JniRefGlobal(jHook); pHook->jObj = S3JniRefGlobal(jHook);
} }
@ -2501,7 +2508,7 @@ static int s3jni_commit_rollback_hook_impl(int isCommit,
S3JniExceptionClear; S3JniExceptionClear;
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, "hook callback threw."); rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, "hook callback threw.");
} }
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
return rc; return rc;
} }
@ -2634,7 +2641,7 @@ static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int
S3JniExceptionWarnCallbackThrew("SQLITE_CONFIG_SQLLOG callback"); S3JniExceptionWarnCallbackThrew("SQLITE_CONFIG_SQLLOG callback");
S3JniExceptionClear; S3JniExceptionClear;
} }
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
S3JniUnrefLocal(jArg0); S3JniUnrefLocal(jArg0);
S3JniUnrefLocal(jArg1); S3JniUnrefLocal(jArg1);
} }
@ -2656,7 +2663,7 @@ S3JniApi(sqlite3_config() /* for SQLLOG */,
S3JniMutex_Global_enter; S3JniMutex_Global_enter;
if( !jLog ){ if( !jLog ){
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
}else if( pHook->jObj && (*env)->IsSameObject(env, jLog, pHook->jObj) ){ }else if( pHook->jObj && (*env)->IsSameObject(env, jLog, pHook->jObj) ){
/* No-op */ /* No-op */
}else { }else {
@ -2669,7 +2676,7 @@ S3JniApi(sqlite3_config() /* for SQLLOG */,
if( midCallback ){ if( midCallback ){
rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 ); rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 );
if( 0==rc ){ if( 0==rc ){
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
pHook->midCallback = midCallback; pHook->midCallback = midCallback;
pHook->jObj = S3JniRefGlobal(jLog); pHook->jObj = S3JniRefGlobal(jLog);
} }
@ -2718,7 +2725,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
CollationState_xDestroy); CollationState_xDestroy);
sqlite3_free(zName); sqlite3_free(zName);
if( 0==rc ){ if( 0==rc ){
S3JniHook_unref( env, &ps->hooks.collation, 1 ); S3JniHook_unref( &ps->hooks.collation, 1 );
ps->hooks.collation.midCallback = midCallback; ps->hooks.collation.midCallback = midCallback;
ps->hooks.collation.jObj = S3JniRefGlobal(oCollation); ps->hooks.collation.jObj = S3JniRefGlobal(oCollation);
} }
@ -3080,7 +3087,8 @@ static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc,
NativePointerHolder_set(env, &S3NphRefs.sqlite3, ps->jDb, *ppDb) NativePointerHolder_set(env, &S3NphRefs.sqlite3, ps->jDb, *ppDb)
/* As of here, the Java/C connection is complete */; /* As of here, the Java/C connection is complete */;
}else{ }else{
assert( ps->pDb == *ppDb /* set up via s3jni_run_java_auto_extensions() */); assert( ps->pDb==*ppDb
&& "Set up via s3jni_run_java_auto_extensions()" );
} }
}else{ }else{
S3JniDb_set_aside(env, ps); S3JniDb_set_aside(env, ps);
@ -3100,8 +3108,8 @@ S3JniApi(sqlite3_open(),jint,1open)(
int rc; int rc;
rc = s3jni_open_pre(env, &jc, strName, &zName, &ps); rc = s3jni_open_pre(env, &jc, strName, &zName, &ps);
if( 0==rc ){ if( 0==rc ){
rc = sqlite3_open(zName, &pOut); rc = s3jni_open_post(env, jc, ps, &pOut, jOut,
rc = s3jni_open_post(env, jc, ps, &pOut, jOut, rc); sqlite3_open(zName, &pOut));
assert(rc==0 ? pOut!=0 : 1); assert(rc==0 ? pOut!=0 : 1);
sqlite3_free(zName); sqlite3_free(zName);
} }
@ -3270,7 +3278,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
} }
S3JniUnrefLocal(jDbName); S3JniUnrefLocal(jDbName);
S3JniUnrefLocal(jTable); S3JniUnrefLocal(jTable);
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@ -3436,7 +3444,7 @@ static int s3jni_progress_handler_impl(void *pP){
rc = s3jni_db_exception(env, ps, rc, rc = s3jni_db_exception(env, ps, rc,
"sqlite3_progress_handler() callback threw"); "sqlite3_progress_handler() callback threw");
} }
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
return rc; return rc;
} }
@ -3452,7 +3460,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
if( !ps ) return; if( !ps ) return;
S3JniMutex_S3JniDb_enter; S3JniMutex_S3JniDb_enter;
if( n<1 || !jProgress ){ if( n<1 || !jProgress ){
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
sqlite3_progress_handler(ps->pDb, 0, 0, 0); sqlite3_progress_handler(ps->pDb, 0, 0, 0);
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
return; return;
@ -3738,7 +3746,7 @@ int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
S3JniUnrefLocal(s1); S3JniUnrefLocal(s1);
S3JniUnrefLocal(s2); S3JniUnrefLocal(s2);
S3JniUnrefLocal(s3); S3JniUnrefLocal(s3);
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
} }
return rc; return rc;
} }
@ -3753,7 +3761,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
if( !ps ) return SQLITE_MISUSE; if( !ps ) return SQLITE_MISUSE;
S3JniMutex_S3JniDb_enter; S3JniMutex_S3JniDb_enter;
if( !jHook ){ if( !jHook ){
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
rc = sqlite3_set_authorizer( ps->pDb, 0, 0 ); rc = sqlite3_set_authorizer( ps->pDb, 0, 0 );
}else{ }else{
jclass klazz; jclass klazz;
@ -3763,7 +3771,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
return 0; return 0;
} }
S3JniHook_unref(env, pHook, 0); S3JniHook_unref(pHook, 0);
} }
pHook->jObj = S3JniRefGlobal(jHook); pHook->jObj = S3JniRefGlobal(jHook);
klazz = (*env)->GetObjectClass(env, jHook); klazz = (*env)->GetObjectClass(env, jHook);
@ -3782,7 +3790,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
}else{ }else{
rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps); rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
} }
if( rc ) S3JniHook_unref(env, pHook, 0); if( rc ) S3JniHook_unref(pHook, 0);
} }
S3JniMutex_S3JniDb_leave; S3JniMutex_S3JniDb_leave;
return rc; return rc;
@ -3978,7 +3986,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
} }
S3JniUnrefLocal(jPUnref); S3JniUnrefLocal(jPUnref);
S3JniUnrefLocal(jX); S3JniUnrefLocal(jX);
S3JniUnrefLocal(hook.jObj); S3JniHook_localundup(hook);
return rc; return rc;
} }
@ -3986,27 +3994,40 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
JniArgsEnvClass,jobject jDb, jint traceMask, jobject jTracer JniArgsEnvClass,jobject jDb, jint traceMask, jobject jTracer
){ ){
S3JniDb * const ps = S3JniDb_from_java(jDb); S3JniDb * const ps = S3JniDb_from_java(jDb);
S3JniHook * const pHook = ps ? &ps->hooks.trace : 0; int rc;
jclass klazz;
if( !ps ) return SQLITE_MISUSE; if( !ps ) return SQLITE_MISUSE;
else if( !traceMask || !jTracer ){ if( !traceMask || !jTracer ){
S3JniHook_unref(env, pHook, 0); S3JniMutex_S3JniDb_enter;
return (jint)sqlite3_trace_v2(ps->pDb, 0, 0, 0); rc = (jint)sqlite3_trace_v2(ps->pDb, 0, 0, 0);
S3JniHook_unref(&ps->hooks.trace, 0);
S3JniMutex_S3JniDb_leave;
}else{
jclass const klazz = (*env)->GetObjectClass(env, jTracer);
S3JniHook hook = S3JniHook_empty;
hook.midCallback = (*env)->GetMethodID(
env, klazz, "call", "(ILjava/lang/Object;Ljava/lang/Object;)I"
);
S3JniUnrefLocal(klazz);
S3JniIfThrew {
S3JniExceptionClear;
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
"Cannot not find matching call() on "
"TracerCallback object.");
}else{
S3JniMutex_S3JniDb_enter;
hook.jObj = S3JniRefGlobal(jTracer);
rc = sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps);
if( 0==rc ){
S3JniHook_unref(&ps->hooks.trace, 0);
ps->hooks.trace = hook;
}else{
S3JniHook_unref(&hook, 0);
}
S3JniMutex_S3JniDb_leave;
}
} }
klazz = (*env)->GetObjectClass(env, jTracer); return rc;
pHook->midCallback = (*env)->GetMethodID(
env, klazz, "call", "(ILjava/lang/Object;Ljava/lang/Object;)I"
);
S3JniUnrefLocal(klazz);
S3JniIfThrew {
S3JniExceptionClear;
S3JniHook_unref(env, pHook, 0);
return s3jni_db_error(ps->pDb, SQLITE_ERROR,
"Cannot not find matching xCallback() on Tracer object.");
}
pHook->jObj = S3JniRefGlobal(jTracer);
return sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps);
} }
S3JniApi(sqlite3_update_hook(),jobject,1update_1hook)( S3JniApi(sqlite3_update_hook(),jobject,1update_1hook)(
@ -5023,6 +5044,8 @@ Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass){
} }
/* Grab references to various global classes and objects... */ /* Grab references to various global classes and objects... */
SJG.g.cObj = S3JniRefGlobal((*env)->FindClass(env,"java/lang/Object"));
S3JniExceptionIsFatal("Error getting reference to Object class.");
SJG.g.cLong = S3JniRefGlobal((*env)->FindClass(env,"java/lang/Long")); SJG.g.cLong = S3JniRefGlobal((*env)->FindClass(env,"java/lang/Long"));
S3JniExceptionIsFatal("Error getting reference to Long class."); S3JniExceptionIsFatal("Error getting reference to Long class.");

View File

@ -1151,7 +1151,7 @@ public final class SQLite3Jni {
/** /**
In addition to calling the C-level sqlite3_shutdown(), the JNI In addition to calling the C-level sqlite3_shutdown(), the JNI
binding also cleans up all stale per-thread state managed by the binding also cleans up all stale per-thread state managed by the
library, as well as any registered auto-extensions and free up library, as well as any registered auto-extensions, and frees up
various bits of memory. Calling this while database handles or various bits of memory. Calling this while database handles or
prepared statements are still active will leak resources. Trying prepared statements are still active will leak resources. Trying
to use those objects after this routine is called invoked to use those objects after this routine is called invoked
@ -1179,8 +1179,8 @@ public final class SQLite3Jni {
public static native int sqlite3_step(@NotNull sqlite3_stmt stmt); public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
/** /**
Internal impl of the public sqlite3_strglob() method. Neither argument Internal impl of the public sqlite3_strglob() method. Neither
may be NULL and both MUST be NUL-terminated. argument may be NULL and both MUST be NUL-terminated UTF-8.
*/ */
private static native int sqlite3_strglob( private static native int sqlite3_strglob(
@NotNull byte[] glob, @NotNull byte[] txt @NotNull byte[] glob, @NotNull byte[] txt
@ -1197,7 +1197,7 @@ public final class SQLite3Jni {
/** /**
Internal impl of the public sqlite3_strlike() method. Neither Internal impl of the public sqlite3_strlike() method. Neither
argument may be NULL and both MUST be NUL-terminated. argument may be NULL and both MUST be NUL-terminated UTF-8.
*/ */
private static native int sqlite3_strlike( private static native int sqlite3_strlike(
@NotNull byte[] glob, @NotNull byte[] txt, int escChar @NotNull byte[] glob, @NotNull byte[] txt, int escChar
@ -1225,9 +1225,8 @@ public final class SQLite3Jni {
arguments are encapsulated in the final argument to this function. arguments are encapsulated in the final argument to this function.
Unlike the C API, which is documented as always returning 0, this Unlike the C API, which is documented as always returning 0, this
implementation returns SQLITE_NOMEM if allocation of per-db implementation returns non-0 if initialization of the tracer
mapping state fails and SQLITE_ERROR if the given callback object mapping state fails.
cannot be processed propertly (i.e. an internal error).
*/ */
public static native int sqlite3_trace_v2( public static native int sqlite3_trace_v2(
@NotNull sqlite3 db, int traceMask, @Nullable TraceV2Callback tracer @NotNull sqlite3 db, int traceMask, @Nullable TraceV2Callback tracer

View File

@ -1,5 +1,5 @@
C Factor\sout\san\sunnecessary\sstruct\smember.\sJNI\ssqlite3_shutdown()\snow\sfrees\sup\sthe\svarious\sobject-recycling\sbins.\sDoc\stouchups. C Make\sJNI\ssqlite3_trace_v2()\sthread-safe.\sRe-add\sa\spiece\sremoved\sin\s[bae4d022aad9b]\sto\swork\saround\sa\sJVM\scrash\swhich\sis\sunpredictably\striggered\sby\sits\ssubstitute.\sFix\sthe\sTHREADMODE=0\sJNI\sbuild.\sFurther\sinternal\sAPI\ssimplifications.
D 2023-08-27T09:12:50.224 D 2023-08-27T10:40:00.984
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
@ -233,10 +233,10 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile 05a756bb7a579b7d6570cb590567e9f0d12270529a2e7e50523284e5a3684838 F ext/jni/GNUmakefile 527f7c72360ba081c9ad120a9a00834973dac0115c6272fad94963651ed15bab
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 b0b86b214477ee1604caf358fd1f232ee6649d327527063dddc22216026c20d2 F ext/jni/src/c/sqlite3-jni.c 79360ee5b71ce2d90e712768456756e5d57c63bce4e8238c23417caabb790a92
F ext/jni/src/c/sqlite3-jni.h a410d05ca47a676b75ff7b8980e75ad604ea15f3c29965f88989703abc2eeaf6 F ext/jni/src/c/sqlite3-jni.h a410d05ca47a676b75ff7b8980e75ad604ea15f3c29965f88989703abc2eeaf6
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 0a5a74bea5ee12a99407e9432d0ca393525af912c2b0ca55c7ee5dbd019c00ef F ext/jni/src/org/sqlite/jni/AggregateFunction.java 0a5a74bea5ee12a99407e9432d0ca393525af912c2b0ca55c7ee5dbd019c00ef
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030 F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030
@ -262,7 +262,7 @@ F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7c
F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java be7f7a26d1102fb514d835e11198d51302af8053d97188bfb2e34c2133208568 F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java be7f7a26d1102fb514d835e11198d51302af8053d97188bfb2e34c2133208568
F ext/jni/src/org/sqlite/jni/SQLFunction.java d060f302b2cc4cf7a4f5a6b2d36458a2e6fc9648374b5d09c36a43665af41207 F ext/jni/src/org/sqlite/jni/SQLFunction.java d060f302b2cc4cf7a4f5a6b2d36458a2e6fc9648374b5d09c36a43665af41207
F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java 13c4ea6f35871261eba63fa4117715515e0beecbdebfb879ec5b1f340ed36904 F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java 13c4ea6f35871261eba63fa4117715515e0beecbdebfb879ec5b1f340ed36904
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 1ae75149383cd8b9fde175aa87855d18e425e32af2bc5e81bf56a95e92155195 F ext/jni/src/org/sqlite/jni/SQLite3Jni.java e27b7b75f561a8a04b222b6306c59e65dcf7c1fc9408523da0d65c1ffb0e1590
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 21301a947e49f0dd9c682dfe2cc8a6518226c837253dd791cd512f847eeca52c F ext/jni/src/org/sqlite/jni/ScalarFunction.java 21301a947e49f0dd9c682dfe2cc8a6518226c837253dd791cd512f847eeca52c
F ext/jni/src/org/sqlite/jni/Tester1.java 37b46dc15ac8fbeb916dcf1f7771023d2be025d05422d725d5891935eda506ac F ext/jni/src/org/sqlite/jni/Tester1.java 37b46dc15ac8fbeb916dcf1f7771023d2be025d05422d725d5891935eda506ac
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
@ -2103,8 +2103,8 @@ 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 0f37f27148dfa93ecc42381ad3455a9059285d1af2df027429044942dc4d861b P bae4d022aad9bbeb78cb027ecad799af87afe331e697add44ec22297c873141d
R e62c13b2db81e23df4398b126d6aa9e9 R 3800367f7606fbafc862156daf2d0dd5
U stephan U stephan
Z aca6efed8b8717dbec6b53005671b2cd Z e92f2dfe5d2f02a04f8aac3861297f02
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
bae4d022aad9bbeb78cb027ecad799af87afe331e697add44ec22297c873141d 3f9f7a9cb08b0687ad206605a5109306762df9ae8bdeab2d8d60bf9373c9ad32