Correct JNI mapping of collations to be 1-db-to-many-collations.
FossilOrigin-Name: b927b0f5a68684b0a9799396d153bf1e2306351e8039c2bacb3d5b2056a0634f
This commit is contained in:
parent
35c7f538e9
commit
a08f737503
@ -429,7 +429,6 @@ struct S3JniDb {
|
||||
SQLITE_DBCONFIG_MAINDBNAME. */;
|
||||
struct {
|
||||
S3JniHook busyHandler;
|
||||
S3JniHook collation;
|
||||
S3JniHook collationNeeded;
|
||||
S3JniHook commit;
|
||||
S3JniHook progress;
|
||||
@ -1021,12 +1020,14 @@ static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx){
|
||||
** problem extracting the exception's message, it's treated as
|
||||
** non-fatal and zDfltMsg is used in its place.
|
||||
**
|
||||
** Locks the global S3JniDb mutex.
|
||||
**
|
||||
** This must only be called if a JNI exception is pending.
|
||||
**
|
||||
** Returns errCode unless it is 0, in which case SQLITE_ERROR is
|
||||
** returned.
|
||||
*/
|
||||
static int s3jni_db_exception(JNIEnv * const env, S3JniDb * const ps,
|
||||
static int s3jni__db_exception(JNIEnv * const env, S3JniDb * const ps,
|
||||
int errCode, const char *zDfltMsg){
|
||||
jthrowable const ex = (*env)->ExceptionOccurred(env);
|
||||
|
||||
@ -1034,13 +1035,17 @@ static int s3jni_db_exception(JNIEnv * const env, S3JniDb * const ps,
|
||||
if( ex ){
|
||||
char * zMsg;
|
||||
S3JniExceptionClear;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
zMsg = s3jni_exception_error_msg(env, ex);
|
||||
s3jni_db_error(ps->pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
sqlite3_free(zMsg);
|
||||
S3JniUnrefLocal(ex);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
return errCode;
|
||||
}
|
||||
#define s3jni_db_exception(JniDb,ERRCODE,DFLTMSG) \
|
||||
s3jni__db_exception(env, (JniDb), (ERRCODE), (DFLTMSG) )
|
||||
|
||||
/*
|
||||
** Extracts the (void xDestroy()) method from jObj and applies it to
|
||||
@ -1049,7 +1054,7 @@ static int s3jni_db_exception(JNIEnv * const env, S3JniDb * const ps,
|
||||
** trigger a warning to stdout or stderr and then the exception is
|
||||
** suppressed.
|
||||
*/
|
||||
static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj){
|
||||
static void s3jni__call_xDestroy(JNIEnv * const env, jobject jObj){
|
||||
if( jObj ){
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jObj);
|
||||
jmethodID method = (*env)->GetMethodID(env, klazz, "xDestroy", "()V");
|
||||
@ -1068,25 +1073,7 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Removes any Java references from s and clears its state. If
|
||||
** doXDestroy is true and s->jObj is not NULL, s->jObj's
|
||||
** s is passed to s3jni_call_xDestroy() before any references are
|
||||
** cleared. It is legal to call this when the object has no Java
|
||||
** references.
|
||||
*/
|
||||
static void S3JniHook_unref_impl(JNIEnv * const env, S3JniHook * const s,
|
||||
int doXDestroy){
|
||||
if( s->jObj ){
|
||||
if( doXDestroy ){
|
||||
s3jni_call_xDestroy(env, s->jObj);
|
||||
}
|
||||
S3JniUnrefGlobal(s->jObj);
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
#define S3JniHook_unref(H,X) S3JniHook_unref_impl(env, (H), (X))
|
||||
#define s3jni_call_xDestroy(JOBJ) s3jni__call_xDestroy(env, (JOBJ))
|
||||
|
||||
/*
|
||||
** Internal helper for many hook callback impls. Locks the S3JniDb
|
||||
@ -1105,15 +1092,36 @@ static void S3JniHook_unref_impl(JNIEnv * const env, S3JniHook * const s,
|
||||
** another thread modify the hook while we're running it. That copy
|
||||
** has to have its own Java reference, but it need only be call-local.
|
||||
*/
|
||||
static void S3JniHook_localdup( JNIEnv * const env, S3JniHook const * const src,
|
||||
S3JniHook * const dest ){
|
||||
static void S3JniHook__localdup( 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;
|
||||
}
|
||||
#define S3JniHook_localdup(src,dest) S3JniHook__localdup(env,src,dest)
|
||||
#define S3JniHook_localundup(HOOK) S3JniUnrefLocal(HOOK.jObj)
|
||||
|
||||
/*
|
||||
** Removes any Java references from s and clears its state. If
|
||||
** doXDestroy is true and s->jObj is not NULL, s->jObj's
|
||||
** s is passed to s3jni_call_xDestroy() before any references are
|
||||
** cleared. It is legal to call this when the object has no Java
|
||||
** references.
|
||||
*/
|
||||
static void S3JniHook__unref(JNIEnv * const env, S3JniHook * const s,
|
||||
int doXDestroy){
|
||||
if( s->jObj ){
|
||||
if( doXDestroy ){
|
||||
s3jni_call_xDestroy(s->jObj);
|
||||
}
|
||||
S3JniUnrefGlobal(s->jObj);
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
#define S3JniHook_unref(hook,doDestroy) \
|
||||
S3JniHook__unref(env, (hook), (doDestroy))
|
||||
|
||||
/*
|
||||
** Clears all of s's state. Requires that that the caller has locked
|
||||
** S3JniGlobal.perDb.mutex. Make sure to do anything needed with
|
||||
@ -1125,7 +1133,6 @@ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
|
||||
#define UNHOOK(MEMBER) S3JniHook_unref(&s->hooks.MEMBER, 0)
|
||||
UNHOOK(auth);
|
||||
UNHOOK(busyHandler);
|
||||
UNHOOK(collation);
|
||||
UNHOOK(collationNeeded);
|
||||
UNHOOK(commit);
|
||||
UNHOOK(progress);
|
||||
@ -1163,10 +1170,11 @@ static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
|
||||
SJG.perDb.aFree = s;
|
||||
}
|
||||
}
|
||||
#define S3JniDb_set_aside_unlocked(JniDb) S3JniDb__set_aside_unlocked(env, JniDb)
|
||||
|
||||
static void S3JniDb__set_aside(JNIEnv * const env, S3JniDb * const s){
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
S3JniDb__set_aside_unlocked(env, s);
|
||||
S3JniDb_set_aside_unlocked(s);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}
|
||||
#define S3JniDb_set_aside(JNIDB) S3JniDb__set_aside(env, JNIDB)
|
||||
@ -1294,10 +1302,8 @@ static jfieldID s3jni_nphop_field(JNIEnv * const env, S3JniNphRef const* pRef){
|
||||
*/
|
||||
static void NativePointerHolder__set(JNIEnv * const env, S3JniNphRef const* pRef,
|
||||
jobject ppOut, const void * p){
|
||||
jfieldID const fid = s3jni_nphop_field(env, pRef);
|
||||
|
||||
assert( ppOut );
|
||||
(*env)->SetLongField(env, ppOut, fid, (jlong)p);
|
||||
(*env)->SetLongField(env, ppOut, s3jni_nphop_field(env, pRef), (jlong)p);
|
||||
S3JniExceptionIsFatal("Could not set NativePointerHolder.nativePointer.");
|
||||
}
|
||||
|
||||
@ -1313,8 +1319,7 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject pObj,
|
||||
S3JniNphRef const* pRef){
|
||||
void * rv = 0;
|
||||
if( pObj ){
|
||||
jfieldID const fid = s3jni_nphop_field(env, pRef);
|
||||
rv = (void*)(*env)->GetLongField(env, pObj, fid);
|
||||
rv = (void*)(*env)->GetLongField(env, pObj, s3jni_nphop_field(env, pRef));
|
||||
S3JniExceptionIsFatal("Cannot fetch NativePointerHolder.nativePointer.");
|
||||
}
|
||||
return rv;
|
||||
@ -1427,7 +1432,7 @@ static S3JniDb * S3JniDb__from_java(JNIEnv * const env, jobject jDb){
|
||||
|
||||
/* An experiment */
|
||||
//#define CLOSE_DB_LOCKED
|
||||
#if defined(CLOSE_DB_LOCKED)
|
||||
#if 1 || defined(CLOSE_DB_LOCKED)
|
||||
static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
|
||||
S3JniDb * s = 0;
|
||||
sqlite3 * pDb = 0;
|
||||
@ -1436,7 +1441,9 @@ static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
|
||||
if( jDb ) pDb = PtrGet_sqlite3(jDb);
|
||||
S3JniDb_search;
|
||||
return s;
|
||||
|
||||
}
|
||||
#define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB))
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1589,45 +1596,44 @@ static int encodingTypeIsValid(int eTextRep){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
State for CollationCallbacks.
|
||||
*/
|
||||
typedef S3JniHook S3JniCollationCallback;
|
||||
|
||||
/*
|
||||
** Proxy for Java-side CollationCallback.xCompare() callbacks.
|
||||
*/
|
||||
static int CollationCallback_xCompare(void *pArg, int nLhs, const void *lhs,
|
||||
int nRhs, const void *rhs){
|
||||
S3JniDb * const ps = pArg;
|
||||
S3JniCollationCallback * const pCC = pArg;
|
||||
S3JniDeclLocal_env;
|
||||
jint rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup(env, &ps->hooks.collation, &hook );
|
||||
if( hook.jObj ){
|
||||
if( pCC->jObj ){
|
||||
jbyteArray jbaLhs = s3jni_new_jbyteArray(lhs, (jint)nLhs);
|
||||
jbyteArray jbaRhs = jbaLhs
|
||||
? s3jni_new_jbyteArray(rhs, (jint)nRhs) : 0;
|
||||
if( !jbaRhs ){
|
||||
S3JniUnrefLocal(jbaLhs);
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
/* We have no recovery strategy here. */
|
||||
s3jni_oom_check( jbaRhs );
|
||||
return 0;
|
||||
}
|
||||
rc = (*env)->CallIntMethod(env, ps->hooks.collation.jObj,
|
||||
ps->hooks.collation.midCallback,
|
||||
rc = (*env)->CallIntMethod(env, pCC->jObj, pCC->midCallback,
|
||||
jbaLhs, jbaRhs);
|
||||
S3JniExceptionIgnore;
|
||||
S3JniUnrefLocal(jbaLhs);
|
||||
S3JniUnrefLocal(jbaRhs);
|
||||
S3JniHook_localundup(hook);
|
||||
}
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
/* CollationCallback finalizer for use by the sqlite3 internals. */
|
||||
static void CollationCallback_xDestroy(void *pArg){
|
||||
S3JniDb * const ps = pArg;
|
||||
S3JniCollationCallback * const pCC = pArg;
|
||||
S3JniDeclLocal_env;
|
||||
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
S3JniHook_unref(&ps->hooks.collation, 1);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
S3JniHook_unref(pCC, 1);
|
||||
sqlite3_free(pCC);
|
||||
}
|
||||
|
||||
/* For use with sqlite3_result/value_pointer() */
|
||||
@ -1763,11 +1769,13 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
|
||||
static void S3JniUdf_free(JNIEnv * const env, S3JniUdf * const s,
|
||||
int cacheIt){
|
||||
assert( !s->pNext );
|
||||
s3jni_call_xDestroy(env, s->jObj);
|
||||
S3JniUnrefGlobal(s->jObj);
|
||||
sqlite3_free(s->zFuncName);
|
||||
assert( !s->pNext );
|
||||
memset(s, 0, sizeof(*s));
|
||||
if( s->jObj ){
|
||||
s3jni_call_xDestroy(s->jObj);
|
||||
S3JniUnrefGlobal(s->jObj);
|
||||
sqlite3_free(s->zFuncName);
|
||||
assert( !s->pNext );
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
if( cacheIt ){
|
||||
S3JniMutex_Global_enter;
|
||||
s->pNext = S3JniGlobal.udf.aFree;
|
||||
@ -2309,13 +2317,13 @@ static int s3jni_busy_handler(void* pState, int n){
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup(env, &ps->hooks.busyHandler, &hook );
|
||||
S3JniHook_localdup(&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,
|
||||
rc = s3jni_db_exception(ps, SQLITE_ERROR,
|
||||
"sqlite3_busy_handler() callback threw.");
|
||||
}
|
||||
S3JniHook_localundup(hook);
|
||||
@ -2328,33 +2336,42 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.busyHandler : 0;
|
||||
S3JniHook hook = S3JniHook_empty;
|
||||
int rc = 0;
|
||||
|
||||
if( !ps ) return (jint)SQLITE_MISUSE;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
if( jBusy ){
|
||||
if( pHook->jObj && (*env)->IsSameObject(env, pHook->jObj, jBusy) ){
|
||||
/* Same object - this is a no-op. */
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return 0;
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jBusy);
|
||||
hook.jObj = S3JniRefGlobal(jBusy);
|
||||
hook.midCallback = (*env)->GetMethodID(env, klazz, "call", "(I)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
jclass klazz;
|
||||
S3JniHook_unref(pHook, 0);
|
||||
pHook->jObj = S3JniRefGlobal(jBusy);
|
||||
klazz = (*env)->GetObjectClass(env, jBusy);
|
||||
pHook->midCallback = (*env)->GetMethodID(env, klazz, "call", "(I)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniHook_unref(pHook, 0);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
S3JniHook_unref(pHook, 0);
|
||||
}
|
||||
if( 0==rc ){
|
||||
rc = jBusy
|
||||
? sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps)
|
||||
: sqlite3_busy_handler(ps->pDb, 0, 0);
|
||||
if( jBusy ){
|
||||
if( hook.jObj ){ /* Replace handler */
|
||||
rc = sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps);
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
*pHook = hook;
|
||||
hook = S3JniHook_empty;
|
||||
}
|
||||
}/* else no-op */
|
||||
}else{ /* Clear handler */
|
||||
rc = sqlite3_busy_handler(ps->pDb, 0, 0);
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
S3JniHook_unref(&hook, 0);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return rc;
|
||||
}
|
||||
@ -2388,9 +2405,8 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
|
||||
/* Move final entry into this slot. */
|
||||
--SJG.autoExt.nExt;
|
||||
*ax = SJG.autoExt.aExt[SJG.autoExt.nExt];
|
||||
memset(&SJG.autoExt.aExt[SJG.autoExt.nExt], 0,
|
||||
sizeof(S3JniAutoExtension));
|
||||
assert(! SJG.autoExt.aExt[SJG.autoExt.nExt].jObj );
|
||||
memset(&SJG.autoExt.aExt[SJG.autoExt.nExt], 0, sizeof(*ax));
|
||||
assert( !SJG.autoExt.aExt[SJG.autoExt.nExt].jObj );
|
||||
rc = JNI_TRUE;
|
||||
break;
|
||||
}
|
||||
@ -2403,9 +2419,9 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
|
||||
/* Wrapper for sqlite3_close(_v2)(). */
|
||||
static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
|
||||
int rc = 0;
|
||||
|
||||
#ifndef CLOSE_DB_LOCKED
|
||||
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||
|
||||
assert(version == 1 || version == 2);
|
||||
if( ps ){
|
||||
rc = 1==version
|
||||
@ -2429,14 +2445,14 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
|
||||
if( 0!=jDb ){
|
||||
S3JniDb * ps;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
ps = S3JniDb__from_java_unlocked(env, jDb);
|
||||
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(env,ps)
|
||||
/* MUST come after close() because of ps->trace. */;
|
||||
S3JniDb_set_aside_unlocked(ps)
|
||||
/* MUST come after close() because of ps->hooks.trace. */;
|
||||
NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
|
||||
}
|
||||
}else{
|
||||
@ -2478,25 +2494,29 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup(env, &ps->hooks.collationNeeded, &hook );
|
||||
S3JniHook_localdup(&ps->hooks.collationNeeded, &hook );
|
||||
if( hook.jObj ){
|
||||
unsigned int const nName = s3jni_utf16_strlen(z16Name);
|
||||
jstring jName = (*env)->NewString(env, (jchar const *)z16Name, nName);
|
||||
|
||||
s3jni_oom_check( jName );
|
||||
S3JniIfThrew{
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
S3JniExceptionClear;
|
||||
}else{
|
||||
(*env)->CallVoidMethod(env, ps->hooks.collationNeeded.jObj,
|
||||
ps->hooks.collationNeeded.midCallback,
|
||||
ps->jDb, (jint)eTextRep, jName);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionWarnCallbackThrew("sqlite3_collation_needed() callback");
|
||||
s3jni_db_exception(env, ps, 0, "sqlite3_collation_needed() callback threw");
|
||||
jobject jDb;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
jDb = ps->jDb ? S3JniRefLocal(ps->jDb) : 0;
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
if( jDb ){
|
||||
(*env)->CallVoidMethod(env, hook.jObj, hook.midCallback,
|
||||
jDb, (jint)eTextRep, jName);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionWarnCallbackThrew("sqlite3_collation_needed() callback");
|
||||
s3jni_db_exception(ps, 0, "sqlite3_collation_needed() callback threw");
|
||||
}
|
||||
S3JniUnrefLocal(jDb);
|
||||
}
|
||||
S3JniUnrefLocal(jName);
|
||||
}
|
||||
S3JniUnrefLocal(jName);
|
||||
S3JniHook_localundup(hook);
|
||||
}
|
||||
}
|
||||
@ -2504,18 +2524,25 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
|
||||
S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
|
||||
JniArgsEnvClass, jobject jDb, jobject jHook
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||
S3JniHook * const pHook = &ps->hooks.collationNeeded;
|
||||
S3JniDb * ps;
|
||||
S3JniHook * pHook;
|
||||
int rc = 0;
|
||||
|
||||
if( !ps ) return SQLITE_MISUSE;
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
ps = S3JniDb_from_java_unlocked(jDb);
|
||||
if( !ps ){
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
pHook = &ps->hooks.collationNeeded;
|
||||
if( pHook->jObj && jHook &&
|
||||
(*env)->IsSameObject(env, pHook->jObj, jHook) ){
|
||||
/* no-op */
|
||||
}else if( !jHook ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
sqlite3_collation_needed(ps->pDb, 0, 0);
|
||||
rc = sqlite3_collation_needed(ps->pDb, 0, 0);
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
}
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback = (*env)->GetMethodID(
|
||||
@ -2523,13 +2550,12 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
|
||||
);
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = s3jni_db_exception(env, ps, SQLITE_MISUSE,
|
||||
"Cannot not find matching callback on "
|
||||
"collation-needed hook object.");
|
||||
rc = s3jni_db_exception(ps, SQLITE_MISUSE,
|
||||
"Cannot not find matching call() in "
|
||||
"CollationNeededCallback object.");
|
||||
}else{
|
||||
rc = sqlite3_collation_needed16(ps->pDb, ps, s3jni_collation_needed_impl16);
|
||||
if( rc ){
|
||||
}else{
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jHook);
|
||||
@ -2603,15 +2629,17 @@ S3JniApi(sqlite3_column_value(),jobject,1column_1value)(
|
||||
return new_sqlite3_value_wrapper(env, sv);
|
||||
}
|
||||
|
||||
static int s3jni_commit_rollback_hook_impl(int isCommit,
|
||||
S3JniDb * const ps){
|
||||
/*
|
||||
** Impl for both commit hooks (if isCommit is true) or rollback hooks.
|
||||
*/
|
||||
static int s3jni_commit_rollback_hook_impl(int isCommit, S3JniDb * const ps){
|
||||
S3JniDeclLocal_env;
|
||||
int rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup( env, isCommit
|
||||
? &ps->hooks.commit : &ps->hooks.rollback,
|
||||
&hook);
|
||||
S3JniHook_localdup(isCommit
|
||||
? &ps->hooks.commit : &ps->hooks.rollback,
|
||||
&hook);
|
||||
if( hook.jObj ){
|
||||
rc = isCommit
|
||||
? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback)
|
||||
@ -2625,32 +2653,35 @@ static int s3jni_commit_rollback_hook_impl(int isCommit,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* C-to-Java commit hook wrapper. */
|
||||
static int s3jni_commit_hook_impl(void *pP){
|
||||
return s3jni_commit_rollback_hook_impl(1, pP);
|
||||
}
|
||||
|
||||
/* C-to-Java rollback hook wrapper. */
|
||||
static void s3jni_rollback_hook_impl(void *pP){
|
||||
(void)s3jni_commit_rollback_hook_impl(0, pP);
|
||||
}
|
||||
|
||||
static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
jobject jDb, jobject jHook){
|
||||
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||
jclass klazz;
|
||||
S3JniDb * ps;
|
||||
jobject pOld = 0;
|
||||
jmethodID xCallback;
|
||||
S3JniHook * const pHook =
|
||||
isCommit ? &ps->hooks.commit : &ps->hooks.rollback;
|
||||
S3JniHook * pHook;
|
||||
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
ps = S3JniDb_from_java_unlocked(jDb);
|
||||
if( !ps ){
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return 0;
|
||||
}
|
||||
pHook = isCommit ? &ps->hooks.commit : &ps->hooks.rollback;
|
||||
pOld = pHook->jObj;
|
||||
if( pOld && jHook &&
|
||||
(*env)->IsSameObject(env, pOld, jHook) ){
|
||||
return pOld;
|
||||
}
|
||||
if( !jHook ){
|
||||
/* No-op. */
|
||||
}else if( !jHook ){
|
||||
if( pOld ){
|
||||
jobject tmp = S3JniRefLocal(pOld);
|
||||
S3JniUnrefGlobal(pOld);
|
||||
@ -2659,29 +2690,30 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
memset(pHook, 0, sizeof(S3JniHook));
|
||||
if( isCommit ) sqlite3_commit_hook(ps->pDb, 0, 0);
|
||||
else sqlite3_rollback_hook(ps->pDb, 0, 0);
|
||||
return pOld;
|
||||
}
|
||||
klazz = (*env)->GetObjectClass(env, jHook);
|
||||
xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionReport;
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching callback on "
|
||||
"hook object.");
|
||||
}else{
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jHook);
|
||||
if( isCommit ) sqlite3_commit_hook(ps->pDb, s3jni_commit_hook_impl, ps);
|
||||
else sqlite3_rollback_hook(ps->pDb, s3jni_rollback_hook_impl, ps);
|
||||
if( pOld ){
|
||||
jobject tmp = S3JniRefLocal(pOld);
|
||||
S3JniUnrefGlobal(pOld);
|
||||
pOld = tmp;
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionReport;
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() in"
|
||||
"hook object.");
|
||||
}else{
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jHook);
|
||||
if( isCommit ) sqlite3_commit_hook(ps->pDb, s3jni_commit_hook_impl, ps);
|
||||
else sqlite3_rollback_hook(ps->pDb, s3jni_rollback_hook_impl, ps);
|
||||
if( pOld ){
|
||||
jobject tmp = S3JniRefLocal(pOld);
|
||||
S3JniUnrefGlobal(pOld);
|
||||
pOld = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return pOld;
|
||||
}
|
||||
|
||||
@ -2733,7 +2765,7 @@ static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int
|
||||
S3JniHook hook = S3JniHook_empty;
|
||||
|
||||
if( ps ){
|
||||
S3JniHook_localdup(env, &SJG.hooks.sqllog, &hook);
|
||||
S3JniHook_localdup(&SJG.hooks.sqllog, &hook);
|
||||
}
|
||||
if( !hook.jObj ) return;
|
||||
jArg0 = S3JniRefLocal(ps->jDb);
|
||||
@ -2775,7 +2807,10 @@ S3JniApi(sqlite3_config() /* for SQLLOG */,
|
||||
|
||||
S3JniMutex_Global_enter;
|
||||
if( !jLog ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 );
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
}
|
||||
}else if( pHook->jObj && (*env)->IsSameObject(env, jLog, pHook->jObj) ){
|
||||
/* No-op */
|
||||
}else {
|
||||
@ -2825,26 +2860,28 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
|
||||
midCallback = (*env)->GetMethodID(env, klazz, "call", "([B[B)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew{
|
||||
S3JniUnrefLocal(klazz);
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Could not get xCompare() method for object.");
|
||||
"Could not get call() method from "
|
||||
"CollationCallback object.");
|
||||
}else{
|
||||
char * const zName = s3jni_jstring_to_utf8( name, 0);
|
||||
if( zName ){
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
S3JniCollationCallback * const pCC =
|
||||
zName ? s3jni_malloc(sizeof(S3JniCollationCallback)) : 0;
|
||||
if( pCC ){
|
||||
memset( pCC, 0, sizeof(*pCC) );
|
||||
rc = sqlite3_create_collation_v2(ps->pDb, zName, (int)eTextRep,
|
||||
ps, CollationCallback_xCompare,
|
||||
pCC, CollationCallback_xCompare,
|
||||
CollationCallback_xDestroy);
|
||||
sqlite3_free(zName);
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref( &ps->hooks.collation, 1 );
|
||||
ps->hooks.collation.midCallback = midCallback;
|
||||
ps->hooks.collation.jObj = S3JniRefGlobal(oCollation);
|
||||
pCC->midCallback = midCallback;
|
||||
pCC->jObj = S3JniRefGlobal(oCollation);
|
||||
}else{
|
||||
CollationCallback_xDestroy(pCC);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3_free(zName);
|
||||
}
|
||||
return (jint)rc;
|
||||
}
|
||||
@ -3363,7 +3400,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
const int isPre = 0!=pDb;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup(env, isPre ?
|
||||
S3JniHook_localdup(isPre ?
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
&ps->hooks.preUpdate
|
||||
#else
|
||||
@ -3392,7 +3429,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
(jint)opId, jDbName, jTable, (jlong)iKey1);
|
||||
S3JniIfThrew{
|
||||
S3JniExceptionWarnCallbackThrew("sqlite3_(pre)update_hook() callback");
|
||||
s3jni_db_exception(env, ps, 0,
|
||||
s3jni_db_exception(ps, 0,
|
||||
"sqlite3_(pre)update_hook() callback threw");
|
||||
}
|
||||
}
|
||||
@ -3516,19 +3553,21 @@ S3JniApi(sqlite3_preupdate_hook(),jobject,1preupdate_1hook)(
|
||||
static int s3jni_preupdate_newold(JNIEnv * const env, int isNew, jobject jDb,
|
||||
jint iCol, jobject jOut){
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
sqlite3_value * pOut = 0;
|
||||
sqlite3 * const pDb = PtrGet_sqlite3(jDb);
|
||||
int rc;
|
||||
int (*fOrig)(sqlite3*,int,sqlite3_value**) =
|
||||
isNew ? sqlite3_preupdate_new : sqlite3_preupdate_old;
|
||||
rc = fOrig(pDb, (int)iCol, &pOut);
|
||||
if( 0==rc ){
|
||||
jobject pWrap = new_sqlite3_value_wrapper(env, pOut);
|
||||
if( pWrap ){
|
||||
OutputPointer_set_sqlite3_value(env, jOut, pWrap);
|
||||
S3JniUnrefLocal(pWrap);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
int rc = SQLITE_MISUSE;
|
||||
if( pDb ){
|
||||
sqlite3_value * pOut = 0;
|
||||
int (*fOrig)(sqlite3*,int,sqlite3_value**) =
|
||||
isNew ? sqlite3_preupdate_new : sqlite3_preupdate_old;
|
||||
rc = fOrig(pDb, (int)iCol, &pOut);
|
||||
if( 0==rc ){
|
||||
jobject pWrap = new_sqlite3_value_wrapper(env, pOut);
|
||||
if( pWrap ){
|
||||
OutputPointer_set_sqlite3_value(env, jOut, pWrap);
|
||||
S3JniUnrefLocal(pWrap);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@ -3557,11 +3596,11 @@ static int s3jni_progress_handler_impl(void *pP){
|
||||
S3JniDeclLocal_env;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup( env, &ps->hooks.progress, &hook );
|
||||
S3JniHook_localdup(&ps->hooks.progress, &hook);
|
||||
if( hook.jObj ){
|
||||
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_exception(env, ps, rc,
|
||||
rc = s3jni_db_exception(ps, rc,
|
||||
"sqlite3_progress_handler() callback threw");
|
||||
}
|
||||
S3JniHook_localundup(hook);
|
||||
@ -3573,8 +3612,6 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
JniArgsEnvClass,jobject jDb, jint n, jobject jProgress
|
||||
){
|
||||
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||
jclass klazz;
|
||||
jmethodID xCallback;
|
||||
S3JniHook * const pHook = ps ? &ps->hooks.progress : 0;
|
||||
|
||||
if( !ps ) return;
|
||||
@ -3582,22 +3619,21 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
if( n<1 || !jProgress ){
|
||||
S3JniHook_unref(pHook, 0);
|
||||
sqlite3_progress_handler(ps->pDb, 0, 0, 0);
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
return;
|
||||
}
|
||||
klazz = (*env)->GetObjectClass(env, jProgress);
|
||||
xCallback = (*env)->GetMethodID(env, klazz, "call", "()I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
S3JniUnrefGlobal(pHook->jObj);
|
||||
pHook->midCallback = xCallback;
|
||||
pHook->jObj = S3JniRefGlobal(jProgress);
|
||||
sqlite3_progress_handler(ps->pDb, (int)n, s3jni_progress_handler_impl, ps);
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jProgress);
|
||||
jmethodID const xCallback = (*env)->GetMethodID(env, klazz, "call", "()I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
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;
|
||||
}
|
||||
@ -3752,7 +3788,7 @@ S3JniApi(sqlite3_result_error(),void,1result_1error)(
|
||||
S3JniApi(sqlite3_result_error_code(),void,1result_1error_1code)(
|
||||
JniArgsEnvClass, jobject jpCx, jint v
|
||||
){
|
||||
sqlite3_result_error_code(PtrGet_sqlite3_context(jpCx), v ? (int)v : SQLITE_ERROR);
|
||||
sqlite3_result_error_code(PtrGet_sqlite3_context(jpCx), (int)v);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_result_error_nomem(),void,1result_1error_1nomem)(
|
||||
@ -3850,7 +3886,7 @@ int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
|
||||
S3JniHook hook;
|
||||
int rc = 0;
|
||||
|
||||
S3JniHook_localdup(env, &ps->hooks.auth, &hook );
|
||||
S3JniHook_localdup(&ps->hooks.auth, &hook );
|
||||
if( hook.jObj ){
|
||||
jstring const s0 = z0 ? s3jni_utf8_to_jstring( z0, -1) : 0;
|
||||
jstring const s1 = z1 ? s3jni_utf8_to_jstring( z1, -1) : 0;
|
||||
@ -3860,7 +3896,7 @@ int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
|
||||
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");
|
||||
rc = s3jni_db_exception(ps, rc, "sqlite3_set_authorizer() callback");
|
||||
}
|
||||
S3JniUnrefLocal(s0);
|
||||
S3JniUnrefLocal(s1);
|
||||
@ -3924,6 +3960,52 @@ S3JniApi(sqlite3_set_last_insert_rowid(),void,1set_1last_1insert_1rowid)(
|
||||
(sqlite3_int64)rowId);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
|
||||
JniArgsEnvClass
|
||||
){
|
||||
s3jni_reset_auto_extension(env);
|
||||
/* Free up env cache. */
|
||||
S3JniMutex_Env_enter;
|
||||
while( SJG.envCache.aHead ){
|
||||
S3JniEnv_uncache( SJG.envCache.aHead->env );
|
||||
}
|
||||
S3JniMutex_Env_leave;
|
||||
/* Free up S3JniUdf recycling bin. */
|
||||
S3JniMutex_Global_enter;
|
||||
while( S3JniGlobal.udf.aFree ){
|
||||
S3JniUdf * const u = S3JniGlobal.udf.aFree;
|
||||
S3JniGlobal.udf.aFree = u->pNext;
|
||||
u->pNext = 0;
|
||||
S3JniUdf_free(env, u, 0);
|
||||
}
|
||||
S3JniMutex_Global_leave;
|
||||
/* Free up S3JniDb recycling bin. */
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
while( S3JniGlobal.perDb.aFree ){
|
||||
S3JniDb * const d = S3JniGlobal.perDb.aFree;
|
||||
S3JniGlobal.perDb.aFree = d->pNext;
|
||||
d->pNext = 0;
|
||||
S3JniDb_clear(env, d);
|
||||
sqlite3_free(d);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
#if 0
|
||||
/*
|
||||
** Is automatically closing any still-open dbs a good idea? We will
|
||||
** get rid of the perDb list once sqlite3 gets a per-db client
|
||||
** state, at which point we won't have a central list of databases
|
||||
** to close.
|
||||
*/
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
while( SJG.perDb.pHead ){
|
||||
s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
#endif
|
||||
/* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
|
||||
return sqlite3_shutdown();
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_status(),jint,1status)(
|
||||
JniArgsEnvClass, jint op, jobject jOutCurrent, jobject jOutHigh,
|
||||
jboolean reset
|
||||
@ -3968,54 +4050,6 @@ static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
|
||||
return rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
|
||||
JniArgsEnvClass
|
||||
){
|
||||
s3jni_reset_auto_extension(env);
|
||||
/* Free up env cache. */
|
||||
S3JniMutex_Env_enter;
|
||||
while( SJG.envCache.aHead ){
|
||||
S3JniEnv_uncache( SJG.envCache.aHead->env );
|
||||
}
|
||||
S3JniMutex_Env_leave;
|
||||
/* Free up S3JniUdf recycling bin. */
|
||||
S3JniMutex_Global_enter;
|
||||
while( S3JniGlobal.udf.aFree ){
|
||||
S3JniUdf * const u = S3JniGlobal.udf.aFree;
|
||||
S3JniGlobal.udf.aFree = u->pNext;
|
||||
u->pNext = 0;
|
||||
S3JniUdf_free(env, u, 0);
|
||||
}
|
||||
S3JniMutex_Global_leave;
|
||||
/* Free up S3JniDb recycling bin. */
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
while( S3JniGlobal.perDb.aFree ){
|
||||
S3JniDb * const d = S3JniGlobal.perDb.aFree;
|
||||
S3JniGlobal.perDb.aFree = d->pNext;
|
||||
d->pNext = 0;
|
||||
S3JniDb_clear(env, d);
|
||||
sqlite3_free(d);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** Is automatically closing any still-open dbs a good idea? We will
|
||||
** get rid of the perDb list once sqlite3 gets a per-db client
|
||||
** state, at which point we won't have a central list of databases
|
||||
** to close.
|
||||
*/
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
while( SJG.perDb.pHead ){
|
||||
s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
|
||||
}
|
||||
S3JniMutex_S3JniDb_leave;
|
||||
#endif
|
||||
|
||||
/* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
|
||||
return sqlite3_shutdown();
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_strglob(),jint,1strglob)(
|
||||
JniArgsEnvClass, jbyteArray baG, jbyteArray baT
|
||||
){
|
||||
@ -4061,7 +4095,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
int rc = 0;
|
||||
S3JniHook hook;
|
||||
|
||||
S3JniHook_localdup( env, &ps->hooks.trace, &hook );
|
||||
S3JniHook_localdup(&ps->hooks.trace, &hook );
|
||||
if( !hook.jObj ){
|
||||
return 0;
|
||||
}
|
||||
@ -4092,16 +4126,17 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
/* Create a new temporary sqlite3_stmt wrapper */
|
||||
jP = jPUnref = new_sqlite3_stmt_wrapper(env, pP);
|
||||
if( !jP ){
|
||||
S3JniUnrefLocal(jX);
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
assert(jP);
|
||||
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.");
|
||||
if( 0==rc ){
|
||||
assert(jP);
|
||||
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback,
|
||||
(jint)traceflag, jP, jX);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_exception(ps, SQLITE_ERROR,
|
||||
"sqlite3_trace_v2() callback threw.");
|
||||
}
|
||||
}
|
||||
}
|
||||
S3JniUnrefLocal(jPUnref);
|
||||
@ -4135,8 +4170,8 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
|
||||
"Cannot not find matching call() on "
|
||||
"TracerCallback object.");
|
||||
}else{
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
hook.jObj = S3JniRefGlobal(jTracer);
|
||||
S3JniMutex_S3JniDb_enter;
|
||||
rc = sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps);
|
||||
if( 0==rc ){
|
||||
S3JniHook_unref(&ps->hooks.trace, 0);
|
||||
@ -4349,7 +4384,7 @@ static void Fts5JniAux_free(Fts5JniAux * const s){
|
||||
S3JniDeclLocal_env;
|
||||
if( env ){
|
||||
/*MARKER(("FTS5 aux function cleanup: %s\n", s->zFuncName));*/
|
||||
s3jni_call_xDestroy(env, s->jObj);
|
||||
s3jni_call_xDestroy(s->jObj);
|
||||
S3JniUnrefGlobal(s->jObj);
|
||||
S3JniUnrefGlobal(s->jUserData);
|
||||
}
|
||||
@ -4579,7 +4614,7 @@ static void S3JniFts5AuxData_xDestroy(void *x){
|
||||
S3JniFts5AuxData * const p = x;
|
||||
if( p->jObj ){
|
||||
S3JniDeclLocal_env;
|
||||
s3jni_call_xDestroy(env, p->jObj);
|
||||
s3jni_call_xDestroy(p->jObj);
|
||||
S3JniUnrefGlobal(p->jObj);
|
||||
}
|
||||
sqlite3_free(x);
|
||||
@ -4792,7 +4827,7 @@ JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
|
||||
if( jAux ){
|
||||
/* Emulate how xSetAuxdata() behaves when it cannot alloc
|
||||
** its auxdata wrapper. */
|
||||
s3jni_call_xDestroy(env, jAux);
|
||||
s3jni_call_xDestroy(jAux);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
@ -1498,7 +1498,7 @@ public class Tester1 implements Runnable {
|
||||
|
||||
if( sqlLog ){
|
||||
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
|
||||
int rc = sqlite3_config( new ConfigSqllogCallback() {
|
||||
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
|
||||
@Override public void call(sqlite3 db, String msg, int op){
|
||||
switch(op){
|
||||
case 0: outln("Opening db: ",db); break;
|
||||
@ -1506,7 +1506,12 @@ public class Tester1 implements Runnable {
|
||||
case 2: outln("Closing db: ",db); break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
int rc = sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
rc = sqlite3_config( null );
|
||||
affirm( 0==rc );
|
||||
rc = sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
}else{
|
||||
outln("WARNING: -sqllog is not active because library was built ",
|
||||
|
@ -24,6 +24,14 @@ public interface XDestroyCallback {
|
||||
Must perform any cleanup required by this object. Must not
|
||||
throw. Must not call back into the sqlite3 API, else it might
|
||||
invoke a deadlock.
|
||||
|
||||
WARNING: as a rule, it is never safe to register individual
|
||||
instances with this interface multiple times in the
|
||||
library. e.g., do not register the same CollationCallback with
|
||||
multiple arities or names using sqlite3_create_collation(). If
|
||||
this rule is violated, the library will eventually try to free
|
||||
each individual reference, leading to memory corruption or a
|
||||
crash via duplicate free().
|
||||
*/
|
||||
public void xDestroy();
|
||||
}
|
||||
|
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
||||
C Updates\sto\stestrunner.tcl\sso\sthat\sit\sruns\sfuzztest\susing\smultiple\sjobs.
|
||||
D 2023-08-28T20:14:19.097
|
||||
C Correct\sJNI\smapping\sof\scollations\sto\sbe\s1-db-to-many-collations.
|
||||
D 2023-08-28T20:21:56.713
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -237,7 +237,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
|
||||
F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551
|
||||
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c c92a764a728a3fcd34882defb7517c47af22c9f7fe184113015cdab9fe401c21
|
||||
F ext/jni/src/c/sqlite3-jni.c 3c16035f6d604c17e50a6477b7309ca8885c54cd8a9c85e8c36d2f8b918d71e7
|
||||
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/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
|
||||
@ -264,13 +264,13 @@ F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java c2748ab52856075b053a55b317988d95dc7fb4d3d42520f8c33573effe1cd185
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 440d64e8c4cff53bd3c0cc676381212489198302d7f1aaa535712c2d7163cc69
|
||||
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java a9558165dbb085494705525ef28e41d337d8348bf44259ce1f77cad72547bfdf
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java 21d78aa59bfc5ce5ff242d4bb6f6d2255d162fba8be5859ab87c9201d61433f0
|
||||
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
|
||||
F ext/jni/src/org/sqlite/jni/TraceV2Callback.java 641926b05a772c2c05c842a81aa839053ba4a13b78ef04b402f5705d060c6246
|
||||
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java be2bc96ff4f56b3c1fd18ae7dba9b207b25b6c123b8a5fd2f7aaf3cc208d8b7d
|
||||
F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
|
||||
F ext/jni/src/org/sqlite/jni/WindowFunction.java 488980f4dbb6bdd7067d6cb9c43e4075475e51c54d9b74a5834422654b126246
|
||||
F ext/jni/src/org/sqlite/jni/XDestroyCallback.java 95fb66353e62e4aca8d6ab60e8f14f9235bd10373c34db0a64f5f13f016f0471
|
||||
F ext/jni/src/org/sqlite/jni/XDestroyCallback.java 50c5ca124ef6c6b735a7e136e7a23a557be367e61b56d4aab5777a614ab46cc2
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Canonical.java e55b82c8259b617ff754ac493fd8b79602631d659b87a858b987540e4c4fdf56
|
||||
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java d48ebd7ae6bbb78bd47d54431c85e1521c89b1d3864a2b6eafd9c0e1b2341457
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 6f962a98c9a5c6e9d21c50ae8716b16bdfdc934a191608cbb7e12ea588ddb6af
|
||||
@ -2107,9 +2107,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 ecf07a0144dc6402b1e0924b1775d99dc465b27aa86a2718cac60a9b4c974312 6463192369ff22eb15d4e34590ef55cd8a6f2501227835664816277806bf961b
|
||||
R 31bc738c1437151db584e22f2c509958
|
||||
T +closed 6463192369ff22eb15d4e34590ef55cd8a6f2501227835664816277806bf961b
|
||||
U dan
|
||||
Z 97aabfccc20038ea125aae98b8297d02
|
||||
P ceeabe9f8b31a30c65147fd270b92d43c7842247548cee9de165113991f6c2cf
|
||||
R 68323f68f37601aa48cb5f2c61fd0c0a
|
||||
U stephan
|
||||
Z 6560ea32a29f03de2be1f2fe7d94526d
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
ceeabe9f8b31a30c65147fd270b92d43c7842247548cee9de165113991f6c2cf
|
||||
b927b0f5a68684b0a9799396d153bf1e2306351e8039c2bacb3d5b2056a0634f
|
Loading…
Reference in New Issue
Block a user