]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Start adding JNI-side support for auto extensions, but hit a brick wall which require...
authorstephan <stephan@noemail.net>
Sun, 6 Aug 2023 20:01:30 +0000 (20:01 +0000)
committerstephan <stephan@noemail.net>
Sun, 6 Aug 2023 20:01:30 +0000 (20:01 +0000)
FossilOrigin-Name: 77a32d238e80fe1d237768d88780043a7bd2b3543e6672536254782cbea0039c

ext/jni/README.md
ext/jni/src/c/sqlite3-jni.c
ext/jni/src/c/sqlite3-jni.h
ext/jni/src/org/sqlite/jni/Authorizer.java
ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
manifest
manifest.uuid

index a1a1dadc8b4dd24cf6d8debe2a67d94b99636510..5b985a0550386a77e0dacfa5b10a8806095cab98 100644 (file)
@@ -73,11 +73,12 @@ Golden Rule: _Never_ Throw from Callbacks
 ------------------------------------------------------------------------
 
 JNI bindings which accept client-defined functions _must never throw
-exceptions_. There are _no exceptions_ to this rule. Exceptions are
-reserved for higher-level bindings which are constructed to
-specifically deal with them and ensure that they do not leak C-level
-resources. Some of the JNI bindings are provided as Java functions
-which expect this rule to always hold.
+exceptions_ unless _very explicitly documented_ as being
+throw-safe. Exceptions are generally reserved for higher-level
+bindings which are constructed to specifically deal with them and
+ensure that they do not leak C-level resources. Some of the JNI
+bindings are provided as Java functions which expect this rule to
+always hold.
 
 UTF-8(-ish)
 ------------------------------------------------------------------------
index e7422bfac82942e47fd60307f1c88c9d155e4b91..6a490404f7cc61aa32668aee63ae80a7c64b6292 100644 (file)
@@ -393,6 +393,39 @@ static void NphCacheLine_clear(JNIEnv * const env, NphCacheLine * const p){
   memset(p, 0, sizeof(NphCacheLine));
 }
 
+#define S3JNI_ENABLE_AUTOEXT 0
+#if S3JNI_ENABLE_AUTOEXT
+/*
+  Whether auto extensions are feasible here is currently unknown due
+  to...
+
+  1) JNIEnv/threading issues.  A db instance is mapped to a specific
+  JNIEnv object but auto extensions may be added from any thread.  In
+  such contexts, which JNIEnv do we use for the JNI APIs?
+
+  2) a chicken/egg problem involving the Java/C mapping of the db:
+  when auto extensions are run, the db has not yet been connected to
+  Java. If we do that during the auto-ext, sqlite3_open(_v2)() will not behave
+  properly because they have a different jobject and the API
+  guarantees the user that _that_ object is the one the API will bind
+  the native to.
+
+  If we change the open(_v2()) interfaces to use OutputPointer.sqlite3
+  instead of the client passing in an instance, we could work around
+  (2).
+*/
+typedef struct S3JniAutoExtension S3JniAutoExtension;
+typedef void (*S3JniAutoExtension_xEntryPoint)(sqlite3*);
+struct S3JniAutoExtension {
+  JNIEnv * env;
+  jobject jObj;
+  jmethodID midFunc;
+  S3JniAutoExtension_xEntryPoint xEntryPoint;
+  S3JniAutoExtension *pNext  /* next linked-list entry */;
+  S3JniAutoExtension *pPrev  /* previous linked-list entry */;
+};
+#endif
+
 /** State for various hook callbacks. */
 typedef struct JniHookState JniHookState;
 struct JniHookState{
@@ -476,6 +509,12 @@ static struct {
       unsigned nInverse;
     } udf;
   } metrics;
+#if S3JNI_ENABLE_AUTOEXT
+  struct {
+    S3JniAutoExtension *pHead;
+    int isRunning;
+  } autoExt;
+#endif
 } S3Global;
 
 /**
@@ -1066,6 +1105,22 @@ static PerDbStateJni * PerDbStateJni_for_db(JNIEnv * const env, jobject jDb,
   return s;
 }
 
+#if 0
+/**
+   An alternative form which searches for the PerDbStateJni instance for
+   pDb with no JNIEnv-specific info. This can be (but _should_ it be?)
+   called from the context of a separate JNIEnv than the one mapped
+   to in the returned object. Returns 0 if no match is found.
+*/
+FIXME_THREADING
+static PerDbStateJni * PerDbStateJni_for_db2(sqlite3 *pDb){
+  PerDbStateJni * s = S3Global.perDb.aUsed;
+  for( ; pDb && s; s = s->pNext){
+    if(s->pDb == pDb) return s;
+  }
+  return 0;
+}
+#endif
 
 /**
    Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
@@ -1633,6 +1688,50 @@ WRAP_INT_SVALUE(1value_1numeric_1type, sqlite3_value_numeric_type)
 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 inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
+  return new_NativePointerHolder_object(env, S3ClassNames.sqlite3, sv);
+}
+/*static*/ int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr,
+                                    const struct sqlite3_api_routines *pThunk){
+  S3JniAutoExtension const * pAX = S3Global.autoExt.pHead;
+  jobject jDb;
+  int rc;
+  JNIEnv * env = 0;
+  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) ){
+    *pzErr = sqlite3_mprintf("Could not get current JNIEnv.");
+    return SQLITE_ERROR;
+  }
+  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);
+    IFTHREW {
+      *pzErr = sqlite3_mprintf("auto-extension threw. TODO: extract error message.");
+      rc = SQLITE_ERROR;
+      break;
+    }
+  }
+  UNREF_L(jDb);
+  S3Global.autoExt.isRunning = 0;
+  return rc;
+}
+JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){}
+#endif /* S3JNI_ENABLE_AUTOEXT */
+
 JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt,
                         jint ndx, jbyteArray baData, jint nMax){
   int rc;
index cb42dee57730ffc1d23326a5616a3591981f9542..edb75ae04e766dcbdcc9f8e72e3122ea2dddbd01 100644 (file)
@@ -1104,7 +1104,7 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1filename
  * Method:    sqlite3_db_config
  * Signature: (Lorg/sqlite/jni/sqlite3;ILorg/sqlite/jni/OutputPointer/Int32;)I
  */
-JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1config__Lorg_sqlite_jni_sqlite3_2ILorg_sqlite_jni_OutputPointer_Int32_2
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1config__Lorg_sqlite_jni_sqlite3_2ILorg_sqlite_jni_OutputPointer_00024Int32_2
   (JNIEnv *, jclass, jobject, jint, jobject);
 
 /*
index 3fd6861feca35b5523fddb72ef695219ed09b4d0..114c27fc63e2a03ec359bae09f0b23d45c99272f 100644 (file)
@@ -14,7 +14,7 @@
 package org.sqlite.jni;
 
 /**
-   A wrapper for use with sqlite3_set_authorizer().
+   A callback for use with sqlite3_set_authorizer().
 */
 public interface Authorizer {
   /**
index 15077acdb45ad29a90f9df60fad27e228ab75792..758ea717f090c8bdacad531f1bd086ef1b2263e0 100644 (file)
@@ -70,12 +70,12 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
   public native int xRowCount(@NotNull Fts5Context fcx,
                               @NotNull OutputPointer.Int64 nRow);
   public native long xRowid(@NotNull Fts5Context cx);
-  /* Note that this impl lacks the xDelete() callback
-     argument. Instead, if pAux has an xDestroy() method, it is called
-     if the FTS5 API finalizes the aux state (including if allocation
-     of storage for the auxdata fails). Any reference to pAux held by
-     the JNI layer will be relinquished regardless of whther pAux has
-     an xDestroy() method. */
+  /* Note that the JNI binding lacks the C version's xDelete()
+     callback argument. Instead, if pAux has an xDestroy() method, it
+     is called if the FTS5 API finalizes the aux state (including if
+     allocation of storage for the auxdata fails). Any reference to
+     pAux held by the JNI layer will be relinquished regardless of
+     whether pAux has an xDestroy() method. */
   public native int xSetAuxdata(@NotNull Fts5Context cx, @Nullable Object pAux);
   public native int xTokenize(@NotNull Fts5Context cx, @NotNull byte pText[],
                               @NotNull Fts5.xTokenizeCallback callback);
index d474f54bf3ed216d54f8923e51fd453c35a8fb15..d8f67cd1f9c022c112ea6a41576b5acd9212cce5 100644 (file)
@@ -165,6 +165,26 @@ public final class SQLite3Jni {
   // alphabetized.  The SQLITE_... values. on the other hand, are
   // 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);
+
+
   public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx,
                                       @Nullable byte[] data){
     return (null == data)
@@ -911,7 +931,7 @@ public final class SQLite3Jni {
      to hook in arbitrary C-side code during development and testing
      of this library.
    */
-  public static native void sqlite3_do_something_for_developer();
+  static native void sqlite3_do_something_for_developer();
 
   //////////////////////////////////////////////////////////////////////
   // SQLITE_... constants follow...
index caa0a2ffa868eed6622c5d54fb3fa85fa11ba043..dcdf8f77f92839602f3fcc2d94f8f0b8168dd526 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Doc\scleanups.
-D 2023-08-06T15:01:38.351
+C Start\sadding\sJNI-side\ssupport\sfor\sauto\sextensions,\sbut\shit\sa\sbrick\swall\swhich\srequires\sslightly\sawkward\ssemantics\schanges\sin\sthe\sJNI\sbindings\sfor\ssqlite3_open(_v2)()\sto\sresolve,\sso\sstash\sthis\s#if'd\sout\sfor\sthe\stime\sbeing.
+D 2023-08-06T20:01:30.439
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -231,17 +231,17 @@ F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f4
 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
 F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99
-F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf
-F ext/jni/src/c/sqlite3-jni.c ec7de3a37d7a62598179bc602c2f81f28434264e9d2d62d894c8c4eb41098291
-F ext/jni/src/c/sqlite3-jni.h 58678453c1b6cccb8d728a60f59b2b0819226658376c0b36e025ce8b0fea75c3
-F ext/jni/src/org/sqlite/jni/Authorizer.java 8dde03bbe50896d2f426240a4af4dcb6d98b655af84fe6ed86e637f5d5ac1fc8
+F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d
+F ext/jni/src/c/sqlite3-jni.c e335541e3eac0e337cc22f0b78a040e73c477d41128845ffe4ba8029fc077994
+F ext/jni/src/c/sqlite3-jni.h 2ef601ab7cef00047ef0907e873f8f7bc4bfa6ee510b0435e070eb8ee7b6c6f0
+F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
 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
 F ext/jni/src/org/sqlite/jni/CommitHook.java 87c6a8e5138c61a8eeff018fe16d23f29219150239746032687f245938baca1a
 F ext/jni/src/org/sqlite/jni/Fts5.java 13844685231e8b4840a706db3bed84d5dfcf15be0ae7e809eac40420dba24901
 F ext/jni/src/org/sqlite/jni/Fts5Context.java 0a5a02047a6a1dd3e4a38b0e542a8dd2de365033ba30e6ae019a676305959890
-F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java 9798c6288097f4619ded680fe0961132a3f3d3cbffd7ce22096159f114f28c61
+F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java c908e5fdf6f5d15e388144fcd8160a3f46c18dade749f1b747122d2d37f2e726
 F ext/jni/src/org/sqlite/jni/Fts5Function.java 65cde7151e441fee012250a5e03277de7babcd11a0c308a832b7940574259bcc
 F ext/jni/src/org/sqlite/jni/Fts5PhraseIter.java 6642beda341c0b1b46af4e2d7f6f9ab03a7aede43277b2c92859176d6bce3be9
 F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b55809c26e2b797fb321dfcdbc1298c060
@@ -250,7 +250,7 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java fcece068415b804aa7843534addb3905
 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 eb49c9e5424e80ed1465c184086b3895155eee0828fc1992bfee24b741735638
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 2ee2d3522ab6bec9337653233f5fb50619120cc5b12ce5deb59035ca2502cdcd
 F ext/jni/src/org/sqlite/jni/Tester1.java 04c43f3ec93b362fc1c66430a3125067285259cd4fa5afccdb2fa66b691db8d0
 F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee
 F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
@@ -2082,8 +2082,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 6119289da85ac0c83e2a7236d24bbfff22334d6cf1d852756dc658ad6a75dfec
-R 48b7c494d85b3192affc08b2af78551a
+P 5f56b007704f2aad4cbc6f0ccd1e1f1c974865971f99451352714ee7e077c284
+R 55ff516d4ad7789048494bf17442d9b9
 U stephan
-Z a195dbc9574f42748d3f2a6c1a7b8425
+Z 7da38e0ddc75e18237df446c4596f88f
 # Remove this line to create a well-formed Fossil manifest.
index 7715cf2b1617932d5d7fa7a2daab861ac9bc9b4d..b8a927308bd0e1c9aee454262d7144b8789fc364 100644 (file)
@@ -1 +1 @@
-5f56b007704f2aad4cbc6f0ccd1e1f1c974865971f99451352714ee7e077c284
\ No newline at end of file
+77a32d238e80fe1d237768d88780043a7bd2b3543e6672536254782cbea0039c
\ No newline at end of file