mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-08 19:42:06 +03:00
Improve threading support for all types of JNI-side callback hooks, making them safe to invoke if another thread is busy replacing them.
FossilOrigin-Name: f2af7bbf493fe28d92fc9c77425f8bb9d48c02af9a5eabceb0365c705651e114
This commit is contained in:
@ -337,6 +337,9 @@ struct S3JniHook{
|
||||
/* We lookup the jObj.xDestroy() method as-needed for contexts which
|
||||
** have custom finalizers. */
|
||||
};
|
||||
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
static const S3JniHook S3JniHook_empty = {0,0};
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Per-(sqlite3*) state for various JNI bindings. This state is
|
||||
@ -513,6 +516,8 @@ struct S3JniGlobalType {
|
||||
int nExt /* number of active entries in pExt, all in the
|
||||
first nExt'th array elements. */;
|
||||
sqlite3_mutex * mutex /* mutex for manipulation/traversal of pExt */;
|
||||
const void * locker /* object on whose behalf the mutex is held.
|
||||
Only for sanity checking in debug builds. */;
|
||||
} autoExt;
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
struct {
|
||||
@ -599,10 +604,14 @@ static void s3jni_incr( volatile unsigned int * const p ){
|
||||
#define S3JniMutex_Ext_enter \
|
||||
/*MARKER(("Entering autoExt mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_enter( SJG.autoExt.mutex ); \
|
||||
SJG.autoExt.locker = env; \
|
||||
s3jni_incr( &SJG.metrics.nMutexAutoExt )
|
||||
#define S3JniMutex_Ext_leave \
|
||||
/*MARKER(("Leaving autoExt mutex@%p %s.\n", env));*/ \
|
||||
assert( env == SJG.autoExt.locker ); \
|
||||
sqlite3_mutex_leave( SJG.autoExt.mutex )
|
||||
#define S3JniMutex_Ext_assertLocker \
|
||||
assert( env == SJG.autoExt.locker )
|
||||
#define S3JniMutex_Nph_enter \
|
||||
S3JniMutex_Env_assertNotLocker; \
|
||||
/*MARKER(("Entering NPH mutex@%p %s.\n", env));*/ \
|
||||
@ -630,6 +639,7 @@ static void s3jni_incr( volatile unsigned int * const p ){
|
||||
#define S3JniMutex_Env_assertNotLocker
|
||||
#define S3JniMutex_Env_enter
|
||||
#define S3JniMutex_Env_leave
|
||||
#define S3JniMutex_Ext_assertLocker
|
||||
#define S3JniMutex_Ext_enter
|
||||
#define S3JniMutex_Ext_leave
|
||||
#define S3JniMutex_Nph_enter
|
||||
@ -669,7 +679,7 @@ static JNIEnv * s3jni_env(void){
|
||||
return env;
|
||||
}
|
||||
/* Declares local var env = s3jni_env(). */
|
||||
#define LocalJniGetEnv JNIEnv * const env = s3jni_env()
|
||||
#define S3JniDeclLocal_env JNIEnv * const env = s3jni_env()
|
||||
|
||||
/*
|
||||
** Fetches the S3JniGlobal.envCache row for the given env, allocing a
|
||||
@ -943,6 +953,30 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDest
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
/*
|
||||
** Internal helper for many hook callback impls. Locks the S3JniDb
|
||||
** 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
|
||||
** instead of a copy of the prior GLOBAL ref. Then unlocks the
|
||||
** mutex. If dest->jObj is not NULL when this returns then the caller
|
||||
** is obligated to eventually free the new ref by passing dest->jObj
|
||||
** to S3JniUnrefLocal(). The dest pointer must NOT be passed to
|
||||
** S3JniHook_unref(), as that one assumes that dest->jObj is a GLOBAL
|
||||
** ref.
|
||||
**
|
||||
** Background: when running a hook we need a call-local copy lest
|
||||
** another thread modify the hook while we're running it. That copy
|
||||
** has to haves its own Java reference, but it need only be
|
||||
** call-local.
|
||||
*/
|
||||
static void S3JniHook_copy( JNIEnv * const env, S3JniHook const * const src,
|
||||
S3JniHook * const dest ){
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
*dest = *src;
|
||||
if(dest->jObj) dest->jObj = S3JniRefLocal(dest->jObj);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clears s's state and moves it to the free-list.
|
||||
*/
|
||||
@ -962,18 +996,18 @@ static void S3JniDb_set_aside_unlocked(JNIEnv * env, S3JniDb * const s){
|
||||
}
|
||||
sqlite3_free( s->zMainDbName );
|
||||
#define UNHOOK(MEMBER,XDESTROY) S3JniHook_unref(env, &s->hooks.MEMBER, XDESTROY)
|
||||
UNHOOK(trace, 0);
|
||||
UNHOOK(progress, 0);
|
||||
UNHOOK(commit, 0);
|
||||
UNHOOK(rollback, 0);
|
||||
UNHOOK(update, 0);
|
||||
UNHOOK(auth, 0);
|
||||
UNHOOK(busyHandler, 1);
|
||||
UNHOOK(collation, 1);
|
||||
UNHOOK(collationNeeded, 0);
|
||||
UNHOOK(commit, 0);
|
||||
UNHOOK(progress, 0);
|
||||
UNHOOK(rollback, 0);
|
||||
UNHOOK(trace, 0);
|
||||
UNHOOK(update, 0);
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
UNHOOK(preUpdate, 0);
|
||||
#endif
|
||||
UNHOOK(collation, 1);
|
||||
UNHOOK(collationNeeded, 0);
|
||||
UNHOOK(busyHandler, 1);
|
||||
#undef UNHOOK
|
||||
S3JniUnrefGlobal(s->jDb);
|
||||
memset(s, 0, sizeof(S3JniDb));
|
||||
@ -1205,6 +1239,8 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
|
||||
jobject const jAutoExt){
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jAutoExt);
|
||||
|
||||
S3JniMutex_Ext_assertLocker;
|
||||
assert( env == SJG.autoExt.locker );
|
||||
ax->midFunc = (*env)->GetMethodID(env, klazz, "call",
|
||||
"(Lorg/sqlite/jni/sqlite3;)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
@ -1232,8 +1268,7 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
|
||||
** misbehave.
|
||||
*/
|
||||
static jfieldID setupOutputPointer(JNIEnv * const env, S3NphRef const * pRef,
|
||||
const char * const zTypeSig,
|
||||
jobject const jOut){
|
||||
const char * const zTypeSig){
|
||||
S3JniNphClass * const pNC = S3JniGlobal_nph_cache(env, pRef);
|
||||
if( !pNC->fidValue ){
|
||||
S3JniMutex_Nph_enter;
|
||||
@ -1252,7 +1287,7 @@ static jfieldID setupOutputPointer(JNIEnv * const env, S3NphRef const * pRef,
|
||||
*/
|
||||
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int v){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_Int32, "I", jOut
|
||||
env, &S3NphRefs.OutputPointer_Int32, "I"
|
||||
);
|
||||
(*env)->SetIntField(env, jOut, setter, (jint)v);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.Int32.value");
|
||||
@ -1264,7 +1299,7 @@ static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int
|
||||
*/
|
||||
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlong v){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_Int64, "J", jOut
|
||||
env, &S3NphRefs.OutputPointer_Int64, "J"
|
||||
);
|
||||
(*env)->SetLongField(env, jOut, setter, v);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.Int64.value");
|
||||
@ -1277,7 +1312,7 @@ static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlon
|
||||
static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
|
||||
jobject jDb){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_sqlite3, "Lorg/sqlite/jni/sqlite3;", jOut
|
||||
env, &S3NphRefs.OutputPointer_sqlite3, "Lorg/sqlite/jni/sqlite3;"
|
||||
);
|
||||
(*env)->SetObjectField(env, jOut, setter, jDb);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.sqlite3.value");
|
||||
@ -1291,7 +1326,7 @@ static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOu
|
||||
jobject jStmt){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_sqlite3_stmt,
|
||||
"Lorg/sqlite/jni/sqlite3_stmt;", jOut
|
||||
"Lorg/sqlite/jni/sqlite3_stmt;"
|
||||
);
|
||||
(*env)->SetObjectField(env, jOut, setter, jStmt);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.sqlite3_stmt.value");
|
||||
@ -1306,7 +1341,7 @@ static void OutputPointer_set_sqlite3_value(JNIEnv * const env, jobject const jO
|
||||
jobject jValue){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_sqlite3_value,
|
||||
"Lorg/sqlite/jni/sqlite3_value;", jOut
|
||||
"Lorg/sqlite/jni/sqlite3_value;"
|
||||
);
|
||||
(*env)->SetObjectField(env, jOut, setter, jValue);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.sqlite3_value.value");
|
||||
@ -1322,7 +1357,7 @@ static void OutputPointer_set_sqlite3_value(JNIEnv * const env, jobject const jO
|
||||
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
|
||||
jbyteArray const v){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_ByteArray, "[B", jOut
|
||||
env, &S3NphRefs.OutputPointer_ByteArray, "[B"
|
||||
);
|
||||
(*env)->SetObjectField(env, jOut, setter, v);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.ByteArray.value");
|
||||
@ -1336,7 +1371,7 @@ static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
|
||||
static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
|
||||
jstring const v){
|
||||
jfieldID const setter = setupOutputPointer(
|
||||
env, &S3NphRefs.OutputPointer_String, "Ljava/lang/String;", jOut
|
||||
env, &S3NphRefs.OutputPointer_String, "Ljava/lang/String;"
|
||||
);
|
||||
(*env)->SetObjectField(env, jOut, setter, v);
|
||||
S3JniExceptionIsFatal("Cannot set OutputPointer.String.value");
|
||||
@ -1358,13 +1393,17 @@ static int encodingTypeIsValid(int eTextRep){
|
||||
}
|
||||
|
||||
/*
|
||||
** Proxy for Java-side Collation.xCompare() callbacks.
|
||||
** Proxy for Java-side CollationCallback.xCompare() callbacks.
|
||||
*/
|
||||
static int CollationState_xCompare(void *pArg, int nLhs, const void *lhs,
|
||||
int nRhs, const void *rhs){
|
||||
S3JniDb * const ps = pArg;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
jint rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy(env, &ps->hooks.collation, &hook );
|
||||
if( hook.jObj ){
|
||||
jbyteArray jbaLhs = (*env)->NewByteArray(env, (jint)nLhs);
|
||||
jbyteArray jbaRhs = jbaLhs ? (*env)->NewByteArray(env, (jint)nRhs) : NULL;
|
||||
if( !jbaRhs ){
|
||||
@ -1380,13 +1419,19 @@ static int CollationState_xCompare(void *pArg, int nLhs, const void *lhs,
|
||||
S3JniExceptionIgnore;
|
||||
S3JniUnrefLocal(jbaLhs);
|
||||
S3JniUnrefLocal(jbaRhs);
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
/* Collation finalizer for use by the sqlite3 internals. */
|
||||
static void CollationState_xDestroy(void *pArg){
|
||||
S3JniDb * const ps = pArg;
|
||||
S3JniDeclLocal_env;
|
||||
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
S3JniHook_unref( s3jni_env(), &ps->hooks.collation, 1 );
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1424,7 +1469,7 @@ static ResultJavaVal * ResultJavaVal_alloc(JNIEnv * const env, jobject jObj){
|
||||
static void ResultJavaVal_finalizer(void *v){
|
||||
if( v ){
|
||||
ResultJavaVal * const rv = (ResultJavaVal*)v;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
S3JniUnrefGlobal(rv->jObj);
|
||||
sqlite3_free(rv);
|
||||
}
|
||||
@ -1539,7 +1584,7 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
|
||||
}
|
||||
|
||||
static void S3JniUdf_free(S3JniUdf * s){
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
if( env ){
|
||||
//MARKER(("UDF cleanup: %s\n", s->zFuncName));
|
||||
s3jni_call_xDestroy(env, s->jObj);
|
||||
@ -1652,7 +1697,7 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
|
||||
S3JniUdf * const s,
|
||||
jmethodID xMethodID,
|
||||
const char * const zFuncType){
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
udf_jargs args = {0,0};
|
||||
int rc = udf_args(env, pCx, argc, argv, &args.jcx, &args.jargv);
|
||||
|
||||
@ -1676,7 +1721,7 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
|
||||
static int udf_xFV(sqlite3_context* cx, S3JniUdf * s,
|
||||
jmethodID xMethodID,
|
||||
const char *zFuncType){
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
jobject jcx = new_sqlite3_context_wrapper(env, cx);
|
||||
int rc = 0;
|
||||
int const isFinal = 'F'==zFuncType[1]/*xFinal*/;
|
||||
@ -2044,15 +2089,19 @@ S3JniApi(sqlite3_bind_zeroblob(),jint,1bind_1zeroblob64)(
|
||||
static int s3jni_busy_handler(void* pState, int n){
|
||||
S3JniDb * const ps = (S3JniDb *)pState;
|
||||
int rc = 0;
|
||||
if( ps->hooks.busyHandler.jObj ){
|
||||
LocalJniGetEnv;
|
||||
rc = (*env)->CallIntMethod(env, ps->hooks.busyHandler.jObj,
|
||||
ps->hooks.busyHandler.midCallback, (jint)n);
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy(env, &ps->hooks.busyHandler, &hook );
|
||||
if( hook.jObj ){
|
||||
rc = (*env)->CallIntMethod(env, hook.jObj,
|
||||
hook.midCallback, (jint)n);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionWarnCallbackThrew("sqlite3_busy_handler() callback");
|
||||
rc = s3jni_db_exception(env, ps, SQLITE_ERROR,
|
||||
"sqlite3_busy_handler() callback threw.");
|
||||
}
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -2061,12 +2110,14 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
|
||||
JniArgsEnvClass, jobject jDb, jobject jBusy
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.busyHandler : 0;
|
||||
int rc = 0;
|
||||
if( !ps ) return (jint)SQLITE_NOMEM;
|
||||
if( !ps ) return (jint)SQLITE_MISUSE;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
if( jBusy ){
|
||||
S3JniHook * const pHook = &ps->hooks.busyHandler;
|
||||
if( pHook->jObj && (*env)->IsSameObject(env, pHook->jObj, jBusy) ){
|
||||
/* Same object - this is a no-op. */
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return 0;
|
||||
}
|
||||
jclass klazz;
|
||||
@ -2079,16 +2130,17 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
S3JniHook_unref(env, &ps->hooks.busyHandler, 1);
|
||||
S3JniHook_unref(env, pHook, 1);
|
||||
}
|
||||
return jBusy
|
||||
if( 0==rc ){
|
||||
rc = jBusy
|
||||
? sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps)
|
||||
: sqlite3_busy_handler(ps->pDb, 0, 0);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_busy_timeout(),jint,1busy_1timeout)(
|
||||
JniArgsEnvClass, jobject jDb, jint ms
|
||||
@ -2172,7 +2224,11 @@ static unsigned int s3jni_utf16_strlen(void const * z){
|
||||
static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
|
||||
int eTextRep, const void * z16Name){
|
||||
S3JniDb * const ps = pState;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy(env, &ps->hooks.collationNeeded, &hook );
|
||||
if( hook.jObj ){
|
||||
unsigned int const nName = s3jni_utf16_strlen(z16Name);
|
||||
jstring jName = (*env)->NewString(env, (jchar const *)z16Name, nName);
|
||||
S3JniIfThrew{
|
||||
@ -2187,44 +2243,46 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
|
||||
}
|
||||
S3JniUnrefLocal(jName);
|
||||
}
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
|
||||
JniArgsEnvClass, jobject jDb, jobject jHook
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
jclass klazz;
|
||||
jobject pOld = 0;
|
||||
jmethodID xCallback;
|
||||
S3JniHook * const pHook = &ps->hooks.collationNeeded;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
if( !ps ) return SQLITE_MISUSE;
|
||||
pOld = pHook->jObj;
|
||||
if( pOld && jHook &&
|
||||
(*env)->IsSameObject(env, pOld, jHook) ){
|
||||
return 0;
|
||||
}
|
||||
if( !jHook ){
|
||||
S3JniUnrefGlobal(pOld);
|
||||
memset(pHook, 0, sizeof(S3JniHook));
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
if( pHook->jObj && jHook &&
|
||||
(*env)->IsSameObject(env, pHook->jObj, jHook) ){
|
||||
/* no-op */
|
||||
}else if( !jHook ){
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
sqlite3_collation_needed(ps->pDb, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
klazz = (*env)->GetObjectClass(env, jHook);
|
||||
xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
"(Lorg/sqlite/jni/sqlite3;ILjava/lang/String;)I");
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback = (*env)->GetMethodID(
|
||||
env, klazz, "call", "(Lorg/sqlite/jni/sqlite3;ILjava/lang/String;)I"
|
||||
);
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = s3jni_db_exception(env, ps, SQLITE_MISUSE,
|
||||
"Cannot not find matching callback on "
|
||||
"collation-needed hook object.");
|
||||
}else{
|
||||
rc = sqlite3_collation_needed16(ps->pDb, ps, s3jni_collation_needed_impl16);
|
||||
if( rc ){
|
||||
}else{
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jHook);
|
||||
S3JniUnrefGlobal(pOld);
|
||||
rc = sqlite3_collation_needed16(ps->pDb, ps, s3jni_collation_needed_impl16);
|
||||
}
|
||||
}
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2281,22 +2339,31 @@ S3JniApi(sqlite3_column_text16(),jstring,1column_1text16)(
|
||||
S3JniApi(sqlite3_column_value(),jobject,1column_1value)(
|
||||
JniArgsEnvClass, jobject jpStmt, jint ndx
|
||||
){
|
||||
sqlite3_value * const sv = sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
|
||||
sqlite3_value * const sv =
|
||||
sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
|
||||
return new_sqlite3_value_wrapper(env, sv);
|
||||
}
|
||||
|
||||
|
||||
static int s3jni_commit_rollback_hook_impl(int isCommit, S3JniDb * const ps){
|
||||
LocalJniGetEnv;
|
||||
int rc = isCommit
|
||||
? (int)(*env)->CallIntMethod(env, ps->hooks.commit.jObj,
|
||||
ps->hooks.commit.midCallback)
|
||||
: (int)((*env)->CallVoidMethod(env, ps->hooks.rollback.jObj,
|
||||
ps->hooks.rollback.midCallback), 0);
|
||||
static int s3jni_commit_rollback_hook_impl(int isCommit,
|
||||
S3JniDb * const ps){
|
||||
S3JniDeclLocal_env;
|
||||
int rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy( env,
|
||||
isCommit ? &ps->hooks.commit : &ps->hooks.rollback,
|
||||
&hook);
|
||||
if( hook.jObj ){
|
||||
rc = isCommit
|
||||
? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback)
|
||||
: (int)((*env)->CallVoidMethod(env, hook.jObj, hook.midCallback), 0);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionClear;
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, "hook callback threw.");
|
||||
}
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2400,7 +2467,7 @@ S3JniApi(sqlite3_config() /*for a small subset of options.*/,
|
||||
static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int op){
|
||||
jobject jArg0 = 0;
|
||||
jstring jArg1 = 0;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, 0, pDb);
|
||||
S3JniHook * const hook = &SJG.hooks.sqllog;
|
||||
|
||||
@ -2431,9 +2498,11 @@ void sqlite3_init_sqllog(void){
|
||||
}
|
||||
#endif
|
||||
|
||||
S3JniApi(sqlite3_config(/* for SQLLOG */),
|
||||
S3JniApi(sqlite3_config() /* for SQLLOG */,
|
||||
jint,1config__Lorg_sqlite_jni_SQLLog_2)(JniArgsEnvClass, jobject jLog){
|
||||
#ifdef SQLITE_ENABLE_SQLLOG
|
||||
#ifndef SQLITE_ENABLE_SQLLOG
|
||||
return SQLITE_MISUSE;
|
||||
#else
|
||||
S3JniHook tmpHook;
|
||||
S3JniHook * const hook = &tmpHook;
|
||||
S3JniHook * const hookOld = & SJG.hooks.sqllog;
|
||||
@ -2466,9 +2535,6 @@ S3JniApi(sqlite3_config(/* for SQLLOG */),
|
||||
*hookOld = *hook;
|
||||
}
|
||||
return rc;
|
||||
#else
|
||||
MARKER(("Warning: built without SQLITE_ENABLE_SQLLOG.\n"));
|
||||
return SQLITE_MISUSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2482,32 +2548,35 @@ S3JniApi(sqlite3_context_db_handle(),jobject,1context_1db_1handle)(
|
||||
|
||||
S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
|
||||
jint,1create_1collation
|
||||
)(JniArgsEnvClass, jobject jDb, jstring name, jint eTextRep, jobject oCollation){
|
||||
)(JniArgsEnvClass, jobject jDb, jstring name, jint eTextRep,
|
||||
jobject oCollation){
|
||||
int rc;
|
||||
const char *zName;
|
||||
jclass klazz;
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.collation : 0;
|
||||
jmethodID midCallback;
|
||||
|
||||
if( !pHook ) return SQLITE_MISUSE;
|
||||
if( !ps ) return SQLITE_MISUSE;
|
||||
klazz = (*env)->GetObjectClass(env, oCollation);
|
||||
pHook->midCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
"([B[B)I");
|
||||
midCallback = (*env)->GetMethodID(env, klazz, "call", "([B[B)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew{
|
||||
S3JniUnrefLocal(klazz);
|
||||
return s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Could not get xCompare() method for object.");
|
||||
}
|
||||
}else{
|
||||
zName = s3jni_jstring_to_mutf8(name);
|
||||
rc = sqlite3_create_collation_v2(ps->pDb, zName, (int)eTextRep,
|
||||
ps, CollationState_xCompare,
|
||||
CollationState_xDestroy);
|
||||
s3jni_mutf8_release(name, zName);
|
||||
if( 0==rc ){
|
||||
pHook->jObj = S3JniRefGlobal(oCollation);
|
||||
}else{
|
||||
S3JniHook_unref(env, pHook, 1);
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
S3JniHook_unref( env, &ps->hooks.collation, 1 );
|
||||
ps->hooks.collation.midCallback = midCallback;
|
||||
ps->hooks.collation.jObj = S3JniRefGlobal(oCollation);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
}
|
||||
return (jint)rc;
|
||||
}
|
||||
@ -2564,7 +2633,7 @@ error_cleanup:
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_db_config(/*for MAINDBNAME*/),
|
||||
S3JniApi(sqlite3_db_config() /*for MAINDBNAME*/,
|
||||
jint,1db_1config__Lorg_sqlite_jni_sqlite3_2ILjava_lang_String_2
|
||||
)(JniArgsEnvClass, jobject jDb, jint op, jstring jStr){
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
@ -2573,6 +2642,9 @@ S3JniApi(sqlite3_db_config(/*for MAINDBNAME*/),
|
||||
|
||||
switch( (ps && jStr) ? op : 0 ){
|
||||
case SQLITE_DBCONFIG_MAINDBNAME:
|
||||
S3JniMutex_S3JniDb_enter
|
||||
/* Protect against a race in modifying/freeing
|
||||
ps->zMainDbName. */;
|
||||
zStr = s3jni_jstring_to_utf8(env, jStr, 0);
|
||||
if( zStr ){
|
||||
rc = sqlite3_db_config(ps->pDb, (int)op, zStr);
|
||||
@ -2585,6 +2657,7 @@ S3JniApi(sqlite3_db_config(/*for MAINDBNAME*/),
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
break;
|
||||
default:
|
||||
rc = SQLITE_MISUSE;
|
||||
@ -2909,7 +2982,7 @@ jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self,
|
||||
int rc = SQLITE_ERROR;
|
||||
assert(prepVersion==1 || prepVersion==2 || prepVersion==3);
|
||||
if( !pBuf ){
|
||||
rc = baSql ? SQLITE_MISUSE : SQLITE_NOMEM;
|
||||
rc = baSql ? SQLITE_NOMEM : SQLITE_MISUSE;
|
||||
goto end;
|
||||
}
|
||||
jStmt = new_sqlite3_stmt_wrapper(env, 0);
|
||||
@ -2995,37 +3068,38 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
const char *zDb, const char *zTable,
|
||||
sqlite3_int64 iKey1, sqlite3_int64 iKey2){
|
||||
S3JniDb * const ps = pState;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
jstring jDbName;
|
||||
jstring jTable;
|
||||
S3JniHook * pHook;
|
||||
const int isPre = 0!=pDb;
|
||||
S3JniHook hook;
|
||||
|
||||
pHook = isPre ?
|
||||
S3JniHook_copy(env, isPre ?
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
&ps->hooks.preUpdate
|
||||
#else
|
||||
0
|
||||
&S3JniHook_empty
|
||||
#endif
|
||||
: &ps->hooks.update;
|
||||
|
||||
assert( pHook );
|
||||
: &ps->hooks.update, &hook);
|
||||
if( !hook.jObj ){
|
||||
return;
|
||||
}
|
||||
jDbName = s3jni_utf8_to_jstring(env, zDb, -1);
|
||||
jTable = jDbName ? s3jni_utf8_to_jstring(env, zTable, -1) : 0;
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
}else{
|
||||
assert( pHook->jObj );
|
||||
assert( pHook->midCallback );
|
||||
assert( hook.jObj );
|
||||
assert( hook.midCallback );
|
||||
assert( ps->jDb );
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( isPre ) (*env)->CallVoidMethod(env, pHook->jObj, pHook->midCallback,
|
||||
if( isPre ) (*env)->CallVoidMethod(env, hook.jObj, hook.midCallback,
|
||||
ps->jDb, (jint)opId, jDbName, jTable,
|
||||
(jlong)iKey1, (jlong)iKey2);
|
||||
else
|
||||
#endif
|
||||
(*env)->CallVoidMethod(env, pHook->jObj, pHook->midCallback,
|
||||
(*env)->CallVoidMethod(env, hook.jObj, hook.midCallback,
|
||||
(jint)opId, jDbName, jTable, (jlong)iKey1);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionWarnCallbackThrew("sqlite3_(pre)update_hook() callback");
|
||||
@ -3035,6 +3109,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
}
|
||||
S3JniUnrefLocal(jDbName);
|
||||
S3JniUnrefLocal(jTable);
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
@ -3070,21 +3145,23 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jobject jDb, jobjec
|
||||
jclass klazz;
|
||||
jobject pOld = 0;
|
||||
jmethodID xCallback;
|
||||
S3JniHook * pHook = ps ? (
|
||||
isPre ?
|
||||
S3JniHook * pHook;
|
||||
|
||||
if( !ps ) return 0;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
pHook = isPre ?
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
&ps->hooks.preUpdate
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
: &ps->hooks.update) : 0;
|
||||
|
||||
: &ps->hooks.update;
|
||||
if( !pHook ){
|
||||
return 0;
|
||||
goto end;
|
||||
}
|
||||
pOld = pHook->jObj;
|
||||
if( pOld && jHook && (*env)->IsSameObject(env, pOld, jHook) ){
|
||||
return pOld;
|
||||
goto end;
|
||||
}
|
||||
if( !jHook ){
|
||||
if( pOld ){
|
||||
@ -3098,7 +3175,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jobject jDb, jobjec
|
||||
else
|
||||
#endif
|
||||
sqlite3_update_hook(ps->pDb, 0, 0);
|
||||
return pOld;
|
||||
goto end;
|
||||
}
|
||||
klazz = (*env)->GetObjectClass(env, jHook);
|
||||
xCallback = isPre
|
||||
@ -3130,6 +3207,8 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jobject jDb, jobjec
|
||||
pOld = tmp;
|
||||
}
|
||||
}
|
||||
end:
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return pOld;
|
||||
}
|
||||
|
||||
@ -3185,32 +3264,36 @@ S3JniApi(sqlite3_preupdate_old(),jint,1preupdate_1old)(
|
||||
/* Central C-to-Java sqlite3_progress_handler() proxy. */
|
||||
static int s3jni_progress_handler_impl(void *pP){
|
||||
S3JniDb * const ps = (S3JniDb *)pP;
|
||||
LocalJniGetEnv;
|
||||
int rc = (int)(*env)->CallIntMethod(env, ps->hooks.progress.jObj,
|
||||
ps->hooks.progress.midCallback);
|
||||
int rc = 0;
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy( env, &ps->hooks.progress, &hook );
|
||||
if( hook.jObj ){
|
||||
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_exception(env, ps, rc,
|
||||
"sqlite3_progress_handler() callback threw");
|
||||
}
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
JniArgsEnvClass,jobject jDb, jint n, jobject jProgress
|
||||
){
|
||||
S3JniDb * ps = S3JniDb_for_db(env, jDb, 0);
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
jclass klazz;
|
||||
jmethodID xCallback;
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.progress : 0;
|
||||
|
||||
if( !ps ) return;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
if( n<1 || !jProgress ){
|
||||
if( ps ){
|
||||
S3JniUnrefGlobal(ps->hooks.progress.jObj);
|
||||
memset(&ps->hooks.progress, 0, sizeof(ps->hooks.progress));
|
||||
}
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
sqlite3_progress_handler(ps->pDb, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
if( !ps ){
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return;
|
||||
}
|
||||
klazz = (*env)->GetObjectClass(env, jProgress);
|
||||
@ -3222,22 +3305,19 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
S3JniUnrefGlobal(ps->hooks.progress.jObj);
|
||||
ps->hooks.progress.midCallback = xCallback;
|
||||
ps->hooks.progress.jObj = S3JniRefGlobal(jProgress);
|
||||
S3JniUnrefGlobal(pHook->jObj);
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jProgress);
|
||||
sqlite3_progress_handler(ps->pDb, (int)n, s3jni_progress_handler_impl, ps);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_reset(),jint,1reset)(
|
||||
JniArgsEnvClass, jobject jpStmt
|
||||
){
|
||||
int rc = 0;
|
||||
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
|
||||
if( pStmt ){
|
||||
rc = sqlite3_reset(pStmt);
|
||||
}
|
||||
return rc;
|
||||
return pStmt ? sqlite3_reset(pStmt) : SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* Clears all entries from S3JniGlobal.autoExt. */
|
||||
@ -3479,16 +3559,18 @@ S3JniApi(sqlite3_rollback_hook(),jobject,1rollback_1hook)(
|
||||
int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
|
||||
const char*z2,const char*z3){
|
||||
S3JniDb * const ps = pState;
|
||||
LocalJniGetEnv;
|
||||
S3JniHook const * const pHook = &ps->hooks.auth;
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
int rc = 0;
|
||||
|
||||
S3JniHook_copy(env, &ps->hooks.auth, &hook );
|
||||
if( hook.jObj ){
|
||||
jstring const s0 = z0 ? s3jni_utf8_to_jstring(env, z0, -1) : 0;
|
||||
jstring const s1 = z1 ? s3jni_utf8_to_jstring(env, z1, -1) : 0;
|
||||
jstring const s2 = z2 ? s3jni_utf8_to_jstring(env, z2, -1) : 0;
|
||||
jstring const s3 = z3 ? s3jni_utf8_to_jstring(env, z3, -1) : 0;
|
||||
int rc;
|
||||
|
||||
assert( pHook->jObj );
|
||||
rc = (*env)->CallIntMethod(env, pHook->jObj, pHook->midCallback, (jint)op,
|
||||
rc = (*env)->CallIntMethod(env, hook.jObj, hook.midCallback, (jint)op,
|
||||
s0, s1, s3, s3);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_exception(env, ps, rc, "sqlite3_set_authorizer() callback");
|
||||
@ -3497,6 +3579,8 @@ int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
|
||||
S3JniUnrefLocal(s1);
|
||||
S3JniUnrefLocal(s2);
|
||||
S3JniUnrefLocal(s3);
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3505,17 +3589,19 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.auth : 0;
|
||||
int rc = 0;
|
||||
|
||||
if( !ps ) return SQLITE_MISUSE;
|
||||
else if( !jHook ){
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
if( !jHook ){
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
return (jint)sqlite3_set_authorizer( ps->pDb, 0, 0 );
|
||||
rc = sqlite3_set_authorizer( ps->pDb, 0, 0 );
|
||||
}else{
|
||||
int rc = 0;
|
||||
jclass klazz;
|
||||
if( pHook->jObj ){
|
||||
if( (*env)->IsSameObject(env, pHook->jObj, jHook) ){
|
||||
/* Same object - this is a no-op. */
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return 0;
|
||||
}
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
@ -3533,14 +3619,16 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniHook_unref(env, pHook, 0);
|
||||
return s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of authorizer hook.");
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
|
||||
if( rc ) S3JniHook_unref(env, pHook, 0);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
S3JniApi(sqlite3_set_last_insert_rowid(),void,1set_1last_1insert_1rowid)(
|
||||
@ -3658,15 +3746,21 @@ S3JniApi(sqlite3_step(),jint,1step)(
|
||||
|
||||
static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
S3JniDb * const ps = (S3JniDb *)pC;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
jobject jX = NULL /* the tracer's X arg */;
|
||||
jobject jP = NULL /* the tracer's P arg */;
|
||||
jobject jPUnref = NULL /* potentially a local ref to jP */;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_copy( env, &ps->hooks.trace, &hook );
|
||||
if( !hook.jObj ){
|
||||
return 0;
|
||||
}
|
||||
switch( traceflag ){
|
||||
case SQLITE_TRACE_STMT:
|
||||
jX = s3jni_utf8_to_jstring(env, (const char *)pX, -1);
|
||||
if( !jX ) return SQLITE_NOMEM;
|
||||
if( !jX ) rc = SQLITE_NOMEM;
|
||||
/*MARKER(("TRACE_STMT@%p SQL=%p / %s\n", pP, jX, (const char *)pX));*/
|
||||
break;
|
||||
case SQLITE_TRACE_PROFILE:
|
||||
@ -3674,7 +3768,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
(jlong)*((sqlite3_int64*)pX));
|
||||
// hmm. ^^^ (*pX) really is zero.
|
||||
// MARKER(("profile time = %llu\n", *((sqlite3_int64*)pX)));
|
||||
if( !jX ) return SQLITE_NOMEM;
|
||||
if( !jX ) rc = SQLITE_NOMEM;
|
||||
break;
|
||||
case SQLITE_TRACE_ROW:
|
||||
break;
|
||||
@ -3683,26 +3777,28 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
break;
|
||||
default:
|
||||
assert(!"cannot happen - unkown trace flag");
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
if( 0==rc ){
|
||||
if( !jP ){
|
||||
/* Create a new temporary sqlite3_stmt wrapper */
|
||||
jP = jPUnref = new_sqlite3_stmt_wrapper(env, pP);
|
||||
if( !jP ){
|
||||
S3JniUnrefLocal(jX);
|
||||
return SQLITE_NOMEM;
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert(jP);
|
||||
rc = (int)(*env)->CallIntMethod(env, ps->hooks.trace.jObj,
|
||||
ps->hooks.trace.midCallback,
|
||||
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback,
|
||||
(jint)traceflag, jP, jX);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_exception(env, ps, SQLITE_ERROR,
|
||||
"sqlite3_trace_v2() callback threw.");
|
||||
}
|
||||
}
|
||||
S3JniUnrefLocal(jPUnref);
|
||||
S3JniUnrefLocal(jX);
|
||||
S3JniUnrefLocal(hook.jObj);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3938,7 +4034,7 @@ typedef struct {
|
||||
} Fts5JniAux;
|
||||
|
||||
static void Fts5JniAux_free(Fts5JniAux * const s){
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
if( env ){
|
||||
/*MARKER(("FTS5 aux function cleanup: %s\n", s->zFuncName));*/
|
||||
s3jni_call_xDestroy(env, s->jObj);
|
||||
@ -4102,7 +4198,7 @@ static void s3jni_fts5_extension_function(Fts5ExtensionApi const *pApi,
|
||||
jobject jpFts = 0;
|
||||
jobject jFXA;
|
||||
int rc;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
|
||||
assert(pAux);
|
||||
jFXA = s3jni_getFts5ExensionApi(env);
|
||||
@ -4169,7 +4265,7 @@ static void S3JniFts5AuxData_xDestroy(void *x){
|
||||
if( x ){
|
||||
S3JniFts5AuxData * const p = x;
|
||||
if( p->jObj ){
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
s3jni_call_xDestroy(env, p->jObj);
|
||||
S3JniUnrefGlobal(p->jObj);
|
||||
}
|
||||
@ -4327,7 +4423,7 @@ static int s3jni_xQueryPhrase(const Fts5ExtensionApi *xapi,
|
||||
guaranteed to be the same one passed to xQueryPhrase(). If it's
|
||||
not, we'll have to create a new wrapper object on every call. */
|
||||
struct s3jni_xQueryPhraseState const * s = pData;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
int rc = (int)(*env)->CallIntMethod(env, s->jCallback, s->midCallback,
|
||||
SJG.fts5.jFtsExt, s->jFcx);
|
||||
S3JniIfThrew{
|
||||
@ -4396,9 +4492,10 @@ JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
|
||||
static int s3jni_xTokenize_xToken(void *p, int tFlags, const char* z,
|
||||
int nZ, int iStart, int iEnd){
|
||||
int rc;
|
||||
LocalJniGetEnv;
|
||||
S3JniDeclLocal_env;
|
||||
struct s3jni_xQueryPhraseState * const s = p;
|
||||
jbyteArray jba;
|
||||
|
||||
if( s->tok.zPrev == z && s->tok.nPrev == nZ ){
|
||||
jba = s->tok.jba;
|
||||
}else{
|
||||
|
@ -22,7 +22,8 @@ package org.sqlite.jni;
|
||||
public interface XDestroyCallback {
|
||||
/**
|
||||
Must perform any cleanup required by this object. Must not
|
||||
throw.
|
||||
throw. Must not call back into the sqlite3 API, else it might
|
||||
invoke a deadlock.
|
||||
*/
|
||||
public void xDestroy();
|
||||
}
|
||||
|
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Move\sthe\s3\sJava\sSQLFunction\ssubclasses\sfrom\sinner\sclasses\sto\spackage\sscope.
|
||||
D 2023-08-25T16:43:51.353
|
||||
C Improve\sthreading\ssupport\sfor\sall\stypes\sof\sJNI-side\scallback\shooks,\smaking\sthem\ssafe\sto\sinvoke\sif\sanother\sthread\sis\sbusy\sreplacing\sthem.
|
||||
D 2023-08-26T10:20:38.261
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -236,7 +236,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
|
||||
F ext/jni/GNUmakefile b28f8b304ef97db8250857cb463aea1b329bfcb584a2902d4c1a490a831e2c9d
|
||||
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c 29c10d96f81361b0d121e389320a1dd57958fd758e3790817542d2eb20c42bed
|
||||
F ext/jni/src/c/sqlite3-jni.c b34328504aa8a3e761e097ac3454a665dcb770e577d09f665191d98fe4a5a7b6
|
||||
F ext/jni/src/c/sqlite3-jni.h 2745c4abd0933a4e8cc48989fffbad3936b4eaada64cce9ce11453dcd30e4184
|
||||
F ext/jni/src/org/sqlite/jni/AggregateFunction.java e0aac6ccae05702f8ee779820570866a2760aaa57a73135c57c8d3580bef52d5
|
||||
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030
|
||||
@ -270,7 +270,7 @@ F ext/jni/src/org/sqlite/jni/TraceV2Callback.java 25a45e800b0c57f506c237d111bcfd
|
||||
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java f5eadfa44462c050658230884b41477274f34306accd85c8201a7afbc00d2429
|
||||
F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
|
||||
F ext/jni/src/org/sqlite/jni/WindowFunction.java 3e24a0f2615f9a232b1ecbb3f243b05dd7c007dc43be238499af93a459fe8253
|
||||
F ext/jni/src/org/sqlite/jni/XDestroyCallback.java a43c6fad4d550c40d7ad2545565dd794df68aae855a7a6fe2d5f57ccbfc0e7d6
|
||||
F ext/jni/src/org/sqlite/jni/XDestroyCallback.java 95fb66353e62e4aca8d6ab60e8f14f9235bd10373c34db0a64f5f13f016f0471
|
||||
F ext/jni/src/org/sqlite/jni/fts5_api.java 5198be71c162e3e0cb1f4962a7cdf0d7596e8af53f70c4af6db24aab8d53d9ba
|
||||
F ext/jni/src/org/sqlite/jni/fts5_extension_function.java ac825035d7d83fc7fd960347abfa6803e1614334a21533302041823ad5fc894c
|
||||
F ext/jni/src/org/sqlite/jni/fts5_tokenizer.java a9cce7f9c52803f0d8ee7fb8e40c94e88e980dc24a170e6344b9e5ab0a4411fa
|
||||
@ -2103,8 +2103,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 5786b95f5d09b4462aff0fdeac37992a2b64c47b004d18960f51e4e6a5796106
|
||||
R 7f0497e9841cedff7936a9c02791fa84
|
||||
P 21fd47a68db9df1828f4cc4131d326a193b5751d56a40ae77ed0a78dc0621af1
|
||||
R b5acfb602720e59e7b14d5c62b0da1bf
|
||||
U stephan
|
||||
Z 3ac21aead20aa0563125716a8691ad77
|
||||
Z 1a4a2d91841b9730ebb4db624f2ef288
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
21fd47a68db9df1828f4cc4131d326a193b5751d56a40ae77ed0a78dc0621af1
|
||||
f2af7bbf493fe28d92fc9c77425f8bb9d48c02af9a5eabceb0365c705651e114
|
Reference in New Issue
Block a user