diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 8d88f9f6be..054b04484f 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -397,7 +397,7 @@ static void NphCacheLine_clear(JNIEnv * const env, NphCacheLine * const p){ memset(p, 0, sizeof(NphCacheLine)); } -#define S3JNI_ENABLE_AUTOEXT 0 +#define S3JNI_ENABLE_AUTOEXT 1 #if S3JNI_ENABLE_AUTOEXT /* Whether auto extensions are feasible here is currently unknown due @@ -421,7 +421,6 @@ static void NphCacheLine_clear(JNIEnv * const env, NphCacheLine * const p){ typedef struct S3JniAutoExtension S3JniAutoExtension; typedef void (*S3JniAutoExtension_xEntryPoint)(sqlite3*); struct S3JniAutoExtension { - JNIEnv * env; jobject jObj; jmethodID midFunc; S3JniAutoExtension_xEntryPoint xEntryPoint; @@ -515,8 +514,18 @@ static struct { } metrics; #if S3JNI_ENABLE_AUTOEXT struct { - S3JniAutoExtension *pHead; - int isRunning; + S3JniAutoExtension *pHead /* Head of the auto-extension list */; + PerDbStateJni * psOpening /* handle to the being-opened db. We + need this so that auto extensions + can have a consistent view of the + cross-language db connection and + behave property if they call further + db APIs. */; + int isRunning /* True while auto extensions are + running. This is used to prohibit + manipulation of the auto-extension + list while extensions are + running. */; } autoExt; #endif } S3Global; @@ -738,6 +747,36 @@ static JNIEnvCache * S3Global_env_cache(JNIEnv * const env){ return row; } +/** + Requires jx to be a Throwable. Calls its getMessage() method and + returns its value converted to a UTF-8 string. The caller owns the + returned string and must eventually sqlite3_free() it. Returns 0 + if there is a problem fetching the info or on OOM. +*/ +static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx ){ + JNIEnvCache * const jc = S3Global_env_cache(env); + jmethodID mid; + jstring msg; + char * zMsg; + jclass const klazz = (*env)->GetObjectClass(env, jx); + EXCEPTION_IS_FATAL("Cannot get class of exception object."); + mid = (*env)->GetMethodID(env, klazz, "getMessage", "()Ljava/lang/String;"); + IFTHREW{ + EXCEPTION_REPORT; + EXCEPTION_CLEAR; + return 0; + } + msg = (*env)->CallObjectMethod(env, jx, mid); + IFTHREW{ + EXCEPTION_REPORT; + EXCEPTION_CLEAR; + return 0; + } + zMsg = s3jni_jstring_to_utf8(jc, msg, 0); + UNREF_L(msg); + return zMsg; +} + /** Removes any Java references from s and clears its state. If doXDestroy is true and s->klazz and s->jObj are not NULL, s->jObj's @@ -1131,6 +1170,59 @@ static PerDbStateJni * PerDbStateJni_for_db2(sqlite3 *pDb){ } #endif +#if S3JNI_ENABLE_AUTOEXT +/** + Unlink ax from S3Global.autoExt and free it. +*/ +static void S3JniAutoExtension_free(JNIEnv * const env, + S3JniAutoExtension * const ax){ + if( ax ){ + if( ax->pNext ) ax->pNext->pPrev = ax->pPrev; + if( ax == S3Global.autoExt.pHead ){ + assert( !ax->pNext ); + S3Global.autoExt.pHead = ax->pNext; + }else if( ax->pPrev ){ + ax->pPrev->pNext = ax->pNext; + } + ax->pNext = ax->pPrev = 0; + UNREF_G(ax->jObj); + sqlite3_free(ax); + } +} + +/** + Allocates a new auto extension and plugs it in to S3Global.autoExt. + Returns 0 on OOM or if there is an error collecting the required + state from jAutoExt (which must be an AutoExtension object). +*/ +static S3JniAutoExtension * S3JniAutoExtension_alloc(JNIEnv *const env, + jobject const jAutoExt){ + S3JniAutoExtension * const ax = sqlite3_malloc(sizeof(*ax)); + if( ax ){ + jclass klazz; + memset(ax, 0, sizeof(*ax)); + klazz = (*env)->GetObjectClass(env, jAutoExt); + EXCEPTION_IS_FATAL("Cannot get class of jAutoExt."); + if(!klazz){ + S3JniAutoExtension_free(env, ax); + return 0; + } + ax->midFunc = (*env)->GetMethodID(env, klazz, "xEntryPoint", + "(Lorg/sqlite/jni/sqlite3;)I"); + if(!ax->midFunc){ + MARKER(("Error getting xEntryPoint(sqlite3) from object.")); + S3JniAutoExtension_free(env, ax); + return 0; + } + ax->jObj = REF_G(jAutoExt); + ax->pNext = S3Global.autoExt.pHead; + if( ax->pNext ) ax->pNext->pPrev = ax; + S3Global.autoExt.pHead = ax; + } + return ax; +} +#endif /* S3JNI_ENABLE_AUTOEXT */ + /** Requires that jCx be a Java-side sqlite3_context wrapper for pCx. This function calls sqlite3_aggregate_context() to allocate a tiny @@ -1683,7 +1775,6 @@ static void udf_xInverse(sqlite3_context* cx, int argc, // except for this macro-generated subset which are kept together here // at the front... //////////////////////////////////////////////////////////////////////// -WRAP_INT_DB(1errcode, sqlite3_errcode) WRAP_INT_DB(1error_1offset, sqlite3_error_offset) WRAP_INT_DB(1extended_1errcode, sqlite3_extended_errcode) WRAP_INT_STMT(1bind_1parameter_1count, sqlite3_bind_parameter_count) @@ -1717,44 +1808,71 @@ WRAP_INT_SVALUE(1value_1subtype, sqlite3_value_subtype) WRAP_INT_SVALUE(1value_1type, sqlite3_value_type) #if S3JNI_ENABLE_AUTOEXT -/* auto-extension is very incomplete */ -/*static*/ int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr, - const struct sqlite3_api_routines *pThunk){ +/* Central auto-extension handler. */ +static int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr, + const struct sqlite3_api_routines *ignored){ S3JniAutoExtension const * pAX = S3Global.autoExt.pHead; - jobject jDb; int rc; JNIEnv * env = 0; - if(S3Global.autoExt.isRunning){ + PerDbStateJni * const ps = S3Global.autoExt.psOpening; + + S3Global.autoExt.psOpening = 0; + if( !pAX ){ + assert( 0==S3Global.autoExt.isRunning ); + return 0; + }else if( S3Global.autoExt.isRunning ){ *pzErr = sqlite3_mprintf("Auto-extensions must not be triggered while " "auto-extensions are running."); return SQLITE_MISUSE; - } - if( S3Global.jvm->GetEnv(S3Global.jvm, (void **)&env, JNI_VERSION_1_8) ){ + }else if(!ps){ + MARKER(("Internal error: cannot find PerDbStateJni for auto-extension\n")); + return SQLITE_ERROR; + }else if( (*S3Global.jvm)->GetEnv(S3Global.jvm, (void **)&env, JNI_VERSION_1_8) ){ + assert(!"Cannot get JNIEnv"); *pzErr = sqlite3_mprintf("Could not get current JNIEnv."); return SQLITE_ERROR; } + assert( !ps->pDb /* it's still being opened */ ); + ps->pDb = pDb; + assert( ps->jDb ); + NativePointerHolder_set(env, ps->jDb, pDb, S3ClassNames.sqlite3); S3Global.autoExt.isRunning = 1; - jDb = new_sqlite3_wrapper( env, pDb ); - EXCEPTION_IS_FATAL("Cannot create sqlite3 wrapper object."); - // Now we need PerDbStateJni_for_db(env, jDb, pDb, 1) - // and rewire sqlite3_open(_v2()) to use OutputPointer.sqlite3 - // so that they can have this same jobject. for( ; pAX; pAX = pAX->pNext ){ - JNIEnv * const env = pAX->env - /* ^^^ is this correct, or must we use the JavaVM::GetEnv()'s env - instead? */; - rc = (*env)->CallVoidMethod(env, pAX->jObj, pAX->midFunc, jDb); + rc = (*env)->CallIntMethod(env, pAX->jObj, pAX->midFunc, ps->jDb); IFTHREW { - *pzErr = sqlite3_mprintf("auto-extension threw. TODO: extract error message."); - rc = SQLITE_ERROR; + jthrowable const ex = (*env)->ExceptionOccurred(env); + char * zMsg; + EXCEPTION_CLEAR; + zMsg = s3jni_exception_error_msg(env, ex); + UNREF_L(ex); + *pzErr = sqlite3_mprintf("auto-extension threw: %s", zMsg); + sqlite3_free(zMsg); + rc = rc ? rc : SQLITE_ERROR; + break; + }else if( rc ){ break; } } - UNREF_L(jDb); S3Global.autoExt.isRunning = 0; return rc; } -JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){} + +JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){ + static int once = 0; + S3JniAutoExtension * ax; + + if( !jAutoExt ) return SQLITE_MISUSE; + else if( 0==once && ++once ){ + sqlite3_auto_extension( (void(*)(void))s3jni_auto_extension ); + } + ax = S3Global.autoExt.pHead; + for( ; ax; ax = ax->pNext ){ + if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ + return 0 /* C API treats this as a no-op. */; + } + } + return S3JniAutoExtension_alloc(env, jAutoExt) ? 0 : SQLITE_NOMEM; +} #endif /* S3JNI_ENABLE_AUTOEXT */ JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt, @@ -1879,6 +1997,21 @@ JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){ return SQLITE_MISUSE; } +#if S3JNI_ENABLE_AUTOEXT +JDECL(jboolean,1cancel_1auto_1extension)(JENV_OSELF, jobject jAutoExt){ + S3JniAutoExtension * ax;; + if( S3Global.autoExt.isRunning ) return JNI_FALSE; + for( ax = S3Global.autoExt.pHead; ax; ax = ax->pNext ){ + if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ + S3JniAutoExtension_free(env, ax); + return JNI_TRUE; + } + } + return JNI_FALSE; +} +#endif /* S3JNI_ENABLE_AUTOEXT */ + + /** Wrapper for sqlite3_close(_v2)(). */ @@ -2331,12 +2464,21 @@ JDECL(jstring,1db_1filename)(JENV_CSELF, jobject jDb, jstring jDbName){ return jRv; } +JDECL(jint,1errcode)(JENV_CSELF, jobject jpDb){ + sqlite3 * const pDb = PtrGet_sqlite3(jpDb); + return pDb ? sqlite3_errcode(pDb) : SQLITE_MISUSE; +} + JDECL(jstring,1errmsg)(JENV_CSELF, jobject jpDb){ - return (*env)->NewStringUTF(env, sqlite3_errmsg(PtrGet_sqlite3(jpDb))); + sqlite3 * const pDb = PtrGet_sqlite3(jpDb); + JNIEnvCache * const jc = pDb ? S3Global_env_cache(env) : 0; + return jc ? s3jni_utf8_to_jstring(jc, sqlite3_errmsg(pDb), -1) : 0; } JDECL(jstring,1errstr)(JENV_CSELF, jint rcCode){ - return (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode)); + return (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode)) + /* We know these values to be plain ASCII, so pose no + MUTF-8 incompatibility */; } JDECL(jboolean,1extended_1result_1codes)(JENV_CSELF, jobject jpDb, @@ -2397,6 +2539,12 @@ static int s3jni_open_pre(JNIEnv * const env, JNIEnvCache **jc, return SQLITE_NOMEM; } *ps = PerDbStateJni_alloc(env, 0, *jDb); +#if S3JNI_ENABLE_AUTOEXT + if(*ps){ + assert(!S3Global.autoExt.psOpening); + S3Global.autoExt.psOpening = *ps; + } +#endif return *ps ? 0 : SQLITE_NOMEM; } @@ -2413,8 +2561,15 @@ static int s3jni_open_pre(JNIEnv * const env, JNIEnvCache **jc, */ static int s3jni_open_post(JNIEnv * const env, PerDbStateJni * ps, sqlite3 **ppDb, jobject jOut, int theRc){ +#if S3JNI_ENABLE_AUTOEXT + assert( S3Global.autoExt.pHead ? 0==S3Global.autoExt.psOpening : 1 ); + S3Global.autoExt.psOpening = 0; +#endif if(*ppDb){ assert(ps->jDb); +#if S3JNI_ENABLE_AUTOEXT + assert( S3Global.autoExt.pHead ? *ppDb==ps->pDb : 0==ps->pDb ); +#endif ps->pDb = *ppDb; NativePointerHolder_set(env, ps->jDb, *ppDb, S3ClassNames.sqlite3); }else{ @@ -2598,6 +2753,16 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){ return rc; } +#if S3JNI_ENABLE_AUTOEXT +JDECL(void,1reset_1auto_1extension)(JENV_CSELF){ + if(!S3Global.autoExt.isRunning){ + while( S3Global.autoExt.pHead ){ + S3JniAutoExtension_free(env, S3Global.autoExt.pHead); + } + } +} +#endif /* S3JNI_ENABLE_AUTOEXT */ + /* sqlite3_result_text/blob() and friends. */ static void result_blob_text(int asBlob, int as64, int eTextRep/*only for (asBlob=0)*/, diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 287df65558..01bf381ae0 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -771,6 +771,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_init JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv (JNIEnv *, jclass); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_auto_extension + * Signature: (Lorg/sqlite/jni/AutoExtension;)I + */ +JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1auto_1extension + (JNIEnv *, jclass, jobject); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_bind_blob @@ -867,6 +875,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1handler JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1timeout (JNIEnv *, jclass, jobject, jint); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_cancel_auto_extension + * Signature: (Lorg/sqlite/jni/AutoExtension;)Z + */ +JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1cancel_1auto_1extension + (JNIEnv *, jclass, jobject); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_changes @@ -1259,6 +1275,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1progress_1handler JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset (JNIEnv *, jclass, jobject); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_reset_auto_extension + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset_1auto_1extension + (JNIEnv *, jclass); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_result_double diff --git a/ext/jni/src/org/sqlite/jni/AutoExtension.java b/ext/jni/src/org/sqlite/jni/AutoExtension.java new file mode 100644 index 0000000000..9816a967c2 --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/AutoExtension.java @@ -0,0 +1,29 @@ +/* +** 2023-08-05 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file is part of the JNI bindings for the sqlite3 C API. +*/ +package org.sqlite.jni; + +/** + A callback for use with sqlite3_auto_extension(). +*/ +public interface AutoExtension { + /** + Must function as described for the sqlite3_auto_extension(), + with the caveat that the signature is more limited. + + As an exception to the callbacks-must-not-throw rule, + AutoExtensions may do so and the exception's error + message will be set as the db's error string. + */ + int xEntryPoint(sqlite3 db); +} diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index 68bd4e246a..303ab96662 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -166,24 +166,24 @@ public final class SQLite3Jni { // grouped by category. - // Auto-extensions cannot currently work properly in our setup - // for reasons explained in sqlite3-jni.c. - // - // /** - // Functions almost as documented for the C API, with these - // exceptions: - // - // - The callback interface is more limited because of - // cross-language differences. - // - // - All of the auto-extension routines will fail without side - // effects if invoked from within the execution of an - // auto-extension. - // - // See the AutoExtension class docs for more information. - // */ - // private static native int sqlite3_auto_extension(@NotNull AutoExtension callback); + /** + Functions almost as documented for the C API, with these + exceptions: + - The callback interface is more limited because of + cross-language differences. + + - All of the auto extension routines will fail without side + effects if invoked from within the execution of an + auto-extension. i.e. auto extensions can neither be + added, removed, nor cleared while one is running. + + See the AutoExtension class docs for more information. + + Achtung: it is as yet unknown whether auto extensions registered + from one JNIEnv (thread) can be safely called from another. + */ + public static synchronized native int sqlite3_auto_extension(@NotNull AutoExtension callback); public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data){ @@ -259,6 +259,12 @@ public final class SQLite3Jni { public static native int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms); + /** + Works like the C API except that it returns false, without side + effects, if auto extensions are currently running. + */ + public static synchronized native boolean sqlite3_cancel_auto_extension(@NotNull AutoExtension ax); + public static native int sqlite3_changes(@NotNull sqlite3 db); public static native long sqlite3_changes64(@NotNull sqlite3 db); @@ -584,6 +590,12 @@ public final class SQLite3Jni { public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt); + /** + Works like the C API except that it has no side effects if auto + extensions are currently running. + */ + public static synchronized native void sqlite3_reset_auto_extension(); + public static native void sqlite3_result_double(@NotNull sqlite3_context cx, double v); /** diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index e96038d4d8..f956554a4a 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -58,8 +58,13 @@ public class Tester1 { final OutputPointer.sqlite3 out = new OutputPointer.sqlite3(); int rc = sqlite3_open(":memory:", out); ++metrics.dbOpen; - affirm(0 == rc); sqlite3 db = out.getValue(); + if( 0!=rc ){ + final String msg = db.getNativePointer()==0 + ? sqlite3_errstr(rc) + : sqlite3_errmsg(db); + throw new RuntimeException("Opening db failed: "+msg); + } affirm(0 != db.getNativePointer()); rc = sqlite3_busy_timeout(db, 2000); affirm( 0 == rc ); @@ -979,6 +984,52 @@ public class Tester1 { sqlite3_close(db); } + private static void testAutoExtension(){ + final ValueHolder val = new ValueHolder<>(0); + final ValueHolder toss = new ValueHolder<>(null); + final AutoExtension ax = new AutoExtension(){ + public synchronized int xEntryPoint(sqlite3 db){ + ++val.value; + if( null!=toss.value ){ + throw new RuntimeException(toss.value); + } + return 0; + } + }; + int rc = sqlite3_auto_extension( ax ); + affirm( 0==rc ); + sqlite3_close(createNewDb()); + affirm( 1==val.value ); + sqlite3_close(createNewDb()); + affirm( 2==val.value ); + sqlite3_reset_auto_extension(); + sqlite3_close(createNewDb()); + affirm( 2==val.value ); + rc = sqlite3_auto_extension( ax ); + affirm( 0==rc ); + // Must not add a new entry + rc = sqlite3_auto_extension( ax ); + affirm( 0==rc ); + sqlite3_close( createNewDb() ); + affirm( 3==val.value ); + affirm( sqlite3_cancel_auto_extension(ax) ); + affirm( !sqlite3_cancel_auto_extension(ax) ); + sqlite3_close(createNewDb()); + affirm( 3==val.value ); + rc = sqlite3_auto_extension( ax ); + affirm( 0==rc ); + Exception err = null; + toss.value = "Throwing from AutoExtension."; + try{ + createNewDb(); + }catch(Exception e){ + err = e; + } + affirm( err!=null ); + affirm( err.getMessage().indexOf(toss.value)>0 ); + affirm( sqlite3_cancel_auto_extension(ax) ); + } + private static void testSleep(){ out("Sleeping briefly... "); sqlite3_sleep(600); @@ -1013,6 +1064,7 @@ public class Tester1 { testUpdateHook(); testAuthorizer(); testFts5(); + testAutoExtension(); //testSleep(); if(liArgs.indexOf("-v")>0){ sqlite3_do_something_for_developer(); diff --git a/manifest b/manifest index bdb88221fa..0e7118626b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rework\sthe\ssqlite3_open(_v2)()\sorder\sof\soperations\sso\sthat\spending\sauto-extension\ssupport\scan\sget\sahold\sof\sthe\sopen-time\sJava\sstate\sdespite\sthe\sJava/C\s(sqlite3*)\sbinding\snot\shaving\syet\sbeen\sestablished. -D 2023-08-06T22:09:09.175 +C Bind\sthe\sauto-extension\sAPIs\sto\sJNI. +D 2023-08-07T00:06:31.250 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,9 +232,10 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99 F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d -F ext/jni/src/c/sqlite3-jni.c 21177d7c3492f84aad0666c43ea6d9bc0ebd544f66dcb41219f966b137e86c1b -F ext/jni/src/c/sqlite3-jni.h 2108bb9434fe873e08d6388bce102a474b5c6b00c2ea47d8aee257aca2de2a67 +F ext/jni/src/c/sqlite3-jni.c 406f3fe36661b3628d108a912246b48cafd7fcc1f8b30a563ce6806addb30d71 +F ext/jni/src/c/sqlite3-jni.h 68d219dd351676e819deb38926ebcee0fda141403ce4efa60c3d8bd77993d220 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 +F ext/jni/src/org/sqlite/jni/AutoExtension.java aac84ec21c93306ff5c6ff3b0130de5b76f265dfbc8f7cd158d62cfb8384ff57 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7 @@ -250,8 +251,8 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java 053ea7dbc1234dd70b8948009a52a3f1 F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46 -F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 3edf79fb7a3cb5eaeeaaa074f51521d6d9a962b0dd1ca88074be4fd075258fd8 -F ext/jni/src/org/sqlite/jni/Tester1.java 7ea111e9d52042889f2360e7addfefed4174c1a17dfe6efccf64aaa9a65749cf +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 9af0e0ea79db59d5c4dac13f70031dd5069223d8198f7324f8c1c25e60451e8c +F ext/jni/src/org/sqlite/jni/Tester1.java 63fc2f58b3a5abdad8bd41ff4a1b2572c24fa9246c17a3fcab07dc6adf06ff35 F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d @@ -2082,8 +2083,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 644999caff9db79562d45520d94aaa24ee88c65e397b6fb9c20a4f0e7f84e1a5 -R c4d749cda5fec61bfb97a76dd1b71afd +P 34da294ab558880e81eebd7d261bc590551d5a7d2855e844695cef6394647ea7 +R 8af70828073a693d0f965376a6f73a57 U stephan -Z cb93209a7d6706bee6dfc5cbdd5b5747 +Z 18db46b387e0d752e217b2db93c72ada # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 92f5779fcb..e8b32b32ff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -34da294ab558880e81eebd7d261bc590551d5a7d2855e844695cef6394647ea7 \ No newline at end of file +746a5fa079ad80b3c59411202ee601e0b5c50e79e5994d5e464fa06d3c276324 \ No newline at end of file