]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Bind sqlite3_commit_hook() to JNI.
authorstephan <stephan@noemail.net>
Sun, 30 Jul 2023 05:50:34 +0000 (05:50 +0000)
committerstephan <stephan@noemail.net>
Sun, 30 Jul 2023 05:50:34 +0000 (05:50 +0000)
FossilOrigin-Name: c687297fcae082cbd7f9258c43f3841fd34904d8b62b0adf3cd61fcddeee483d

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/c/sqlite3-jni.h
ext/jni/src/org/sqlite/jni/CommitHook.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
ext/jni/src/org/sqlite/jni/Tester1.java
manifest
manifest.uuid

index 72cfaf209eaf0b66f0214662ea037dbf990c582b..9d923a539305b4b1eee624e1b0617bb6dba0ae16 100644 (file)
 #define PtrGet_sqlite3_context(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_context)
 /* Helpers for Java value reference management. */
 #define REF_G(VAR) (*env)->NewGlobalRef(env, VAR)
-/*#define REF_L(VAR) (*env)->NewLocalRef(env, VAR)*/
+#define REF_L(VAR) (*env)->NewLocalRef(env, VAR)
 #define UNREF_G(VAR) if(VAR) (*env)->DeleteGlobalRef(env, (VAR))
 #define UNREF_L(VAR) if(VAR) (*env)->DeleteLocalRef(env, (VAR))
 
@@ -1512,6 +1512,65 @@ JDECL(jobject,1column_1value)(JENV_JSELF, jobject jpStmt,
   return new_sqlite3_value_wrapper(env, sv);
 }
 
+static int s3jni_commit_hook_impl(void *pP){
+  PerDbStateJni * const ps = (PerDbStateJni *)pP;
+  JNIEnv * const env = ps->env;
+  int rc = (int)(*env)->CallIntMethod(env, ps->commitHook.jObj,
+                                      ps->commitHook.midCallback);
+  IFTHREW{
+    EXCEPTION_CLEAR;
+    rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
+                        "sqlite3_commit_hook() callback threw.");
+  }
+  return rc;
+}
+
+JDECL(jobject,1commit_1hook)(JENV_JSELF,jobject jDb, jobject jCommitHook){
+  sqlite3 * const pDb = PtrGet_sqlite3(jDb);
+  PerDbStateJni * ps = PerDbStateJni_for_db(env, pDb, 1);
+  jclass klazz;
+  jobject pOld = 0;
+  jmethodID xCallback;
+  if(!ps){
+    s3jni_db_error(pDb, SQLITE_NOMEM, 0);
+    return 0;
+  }
+  pOld = ps->commitHook.jObj;
+  if(pOld && jCommitHook &&
+     (*env)->IsSameObject(env, pOld, jCommitHook)){
+    return pOld;
+  }
+  if( !jCommitHook ){
+    if(pOld){
+      jobject tmp = REF_L(pOld);
+      UNREF_G(pOld);
+      pOld = tmp;
+    }
+    memset(&ps->commitHook, 0, sizeof(ps->commitHook));
+    sqlite3_commit_hook(pDb, 0, 0);
+    return pOld;
+  }
+  klazz = (*env)->GetObjectClass(env, jCommitHook);
+  xCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I");
+  IFTHREW {
+    EXCEPTION_CLEAR;
+    s3jni_db_error(pDb, SQLITE_ERROR,
+                   "Cannot not find matching xCallback() on "
+                   "CommitHook object.");
+  }else{
+    ps->commitHook.midCallback = xCallback;
+    ps->commitHook.jObj = REF_G(jCommitHook);
+    sqlite3_commit_hook(pDb, s3jni_commit_hook_impl, ps);
+    if(pOld){
+      jobject tmp = REF_L(pOld);
+      UNREF_G(pOld);
+      pOld = tmp;
+    }
+  }
+  return pOld;
+}
+
+
 JDECL(jstring,1compileoption_1get)(JENV_JSELF, jint n){
   return (*env)->NewStringUTF( env, sqlite3_compileoption_get(n) );
 }
@@ -1744,6 +1803,7 @@ JDECL(void,1progress_1handler)(JENV_JSELF,jobject jDb, jint n, jobject jProgress
   sqlite3 * const pDb = PtrGet_sqlite3(jDb);
   PerDbStateJni * ps = PerDbStateJni_for_db(env, pDb, 1);
   jclass klazz;
+  jmethodID xCallback;
   if( n<1 || !jProgress ){
     if(ps){
       UNREF_G(ps->progress.jObj);
@@ -1757,13 +1817,15 @@ JDECL(void,1progress_1handler)(JENV_JSELF,jobject jDb, jint n, jobject jProgress
     return;
   }
   klazz = (*env)->GetObjectClass(env, jProgress);
-  ps->progress.midCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I");
+  xCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I");
   IFTHREW {
     EXCEPTION_CLEAR;
     s3jni_db_error(pDb, SQLITE_ERROR,
                    "Cannot not find matching xCallback() on "
                    "ProgressHandler object.");
   }else{
+    UNREF_G(ps->progress.jObj);
+    ps->progress.midCallback = xCallback;
     ps->progress.jObj = REF_G(jProgress);
     sqlite3_progress_handler(pDb, (int)n, s3jni_progress_handler_impl, ps);
   }
index 739aea7a87d84181c63b9b1e6a8527b41c8b0bf9..11f0f99e9161335c8df74bc20a2feacd857ddb5c 100644 (file)
@@ -1027,6 +1027,14 @@ JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1value
 JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1context_1db_1handle
   (JNIEnv *, jclass, jobject);
 
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_commit_hook
+ * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/CommitHook;)Lorg/sqlite/jni/CommitHook;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1commit_1hook
+  (JNIEnv *, jclass, jobject, jobject);
+
 /*
  * Class:     org_sqlite_jni_SQLite3Jni
  * Method:    sqlite3_compileoption_get
diff --git a/ext/jni/src/org/sqlite/jni/CommitHook.java b/ext/jni/src/org/sqlite/jni/CommitHook.java
new file mode 100644 (file)
index 0000000..c72d2df
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+** 2023-07-22
+**
+** 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;
+
+/**
+   Callback proxy for use with sqlite3_commit_hook().
+*/
+public interface CommitHook {
+  /**
+     Works as documented for the sqlite3_commit_hook() callback.
+     Must not throw.
+  */
+  int xCallback();
+}
index e3162d7967f6bd989fd8097133d82b123680d9b0..7bcfb70e8805d985cbff7dd3516ea3db026cf41b 100644 (file)
@@ -243,7 +243,7 @@ public final class SQLite3Jni {
 
   public static native sqlite3 sqlite3_context_db_handle(@NotNull sqlite3_context cx);
 
-  //TODO? void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+  public static native CommitHook sqlite3_commit_hook(@NotNull sqlite3 db, @Nullable CommitHook hook);
 
   public static native String sqlite3_compileoption_get(int n);
 
@@ -287,8 +287,6 @@ public final class SQLite3Jni {
 
   public static native long sqlite3_last_insert_rowid(@NotNull sqlite3 db);
 
-  //TODO? void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
-
   public static native String sqlite3_libversion();
 
   public static native int sqlite3_libversion_number();
@@ -397,6 +395,8 @@ public final class SQLite3Jni {
   public static native void sqlite3_progress_handler(@NotNull sqlite3 db, int n,
                                                      @Nullable ProgressHandler h);
 
+  //TODO??? void *sqlite3_preupdate_hook(...) and friends
+
   public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt);
 
   public static native void sqlite3_result_double(@NotNull sqlite3_context cx, double v);
@@ -631,11 +631,7 @@ public final class SQLite3Jni {
     sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16BE);
   }
 
-  /**
-  public static void sqlite3_result_text64(@NotNull sqlite3_context cx,
-                                           @Nullable byte[] text){
-    sqlite3_result_text64(cx, text, null==text ? 0 : text.length, SQLITE_UTF8);
-  }**/
+  //TODO void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
 
   public static native void sqlite3_set_last_insert_rowid(@NotNull sqlite3 db, long rowid);
 
@@ -664,6 +660,8 @@ public final class SQLite3Jni {
   public static native int sqlite3_trace_v2(@NotNull sqlite3 db, int traceMask,
                                             @Nullable Tracer tracer);
 
+  //TODO void *sqlite3_update_hook(sqlite3*,  void(*)(void *,int ,char const *,char const *,sqlite3_int64), void*);
+
   public static native byte[] sqlite3_value_blob(@NotNull sqlite3_value v);
 
   public static native int sqlite3_value_bytes(@NotNull sqlite3_value v);
index 7cc88154365568a93ba3b265170b53da7a12c945..f753a22e4ad1c05a8c6c7f329fd38eb141c4b00d 100644 (file)
@@ -741,6 +741,50 @@ public class Tester1 {
     sqlite3_close_v2(db);
   }
 
+  private static void testCommitHook(){
+    final sqlite3 db = createNewDb();
+    final ValueHolder<Integer> counter = new ValueHolder<>(0);
+    final CommitHook theHook = new CommitHook(){
+        public int xCallback(){
+          ++counter.value;
+          return 0;
+        }
+      };
+    CommitHook oldHook = sqlite3_commit_hook(db, theHook);
+    affirm( null == oldHook );
+    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+    affirm( 2 == counter.value );
+    execSql(db, "BEGIN; SELECT 1; SELECT 2; COMMIT;");
+    affirm( 2 == counter.value /* NOT invoked if no changes are made */ );
+    execSql(db, "BEGIN; update t set a='d' where a='c'; COMMIT;");
+    affirm( 3 == counter.value );
+    oldHook = sqlite3_commit_hook(db, theHook);
+    affirm( theHook == oldHook );
+    execSql(db, "BEGIN; update t set a='e' where a='d'; COMMIT;");
+    affirm( 4 == counter.value );
+    oldHook = sqlite3_commit_hook(db, null);
+    affirm( theHook == oldHook );
+    execSql(db, "BEGIN; update t set a='f' where a='e'; COMMIT;");
+    affirm( 4 == counter.value );
+    oldHook = sqlite3_commit_hook(db, null);
+    affirm( null == oldHook );
+    execSql(db, "BEGIN; update t set a='g' where a='f'; COMMIT;");
+    affirm( 4 == counter.value );
+
+    final CommitHook newHook = new CommitHook(){
+        public int xCallback(){return 0;}
+      };
+    oldHook = sqlite3_commit_hook(db, newHook);
+    affirm( null == oldHook );
+    execSql(db, "BEGIN; update t set a='h' where a='g'; COMMIT;");
+    affirm( 4 == counter.value );
+    oldHook = sqlite3_commit_hook(db, theHook);
+    affirm( newHook == oldHook );
+    execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
+    affirm( 5 == counter.value );
+    sqlite3_close_v2(db);
+  }
+
   private static void testSleep(){
     out("Sleeping briefly... ");
     sqlite3_sleep(600);
@@ -770,6 +814,7 @@ public class Tester1 {
     testTrace();
     testBusy();
     testProgress();
+    testCommitHook();
     //testSleep();
     if(liArgs.indexOf("-v")>0){
       listBoundMethods();
index 0ccad35a874d2c9171b415ad378b02c993bd2d2b..cff3fdf576cc6ca17a43b7a3d568de5b23c2720f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Bind\ssqlite3_progress_handler()\sto\sJNI.\sAdd\ssome\smetrics\sto\sTester1.java.
-D 2023-07-30T04:31:56.673
+C Bind\ssqlite3_commit_hook()\sto\sJNI.
+D 2023-07-30T05:50:34.120
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -232,16 +232,17 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
 F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d
 F ext/jni/README.md b62f1f0e67a6295e9a0283d4dffad6ed30ec50352aa36b3bd323a26593606c0f
-F ext/jni/src/c/sqlite3-jni.c 53fa705d417ab61f4879566352bd1b3e31996aa01d657d6beca597734bff1d0e
-F ext/jni/src/c/sqlite3-jni.h 212c3aede7c9ca8b1116a5d822cb89b95b3d7912452dbe778a9fd6cb869607e3
+F ext/jni/src/c/sqlite3-jni.c bbc85b4bfe8ea05be23771790824f179b17106a806b2507a6b09c2710483f758
+F ext/jni/src/c/sqlite3-jni.h 2d6ec0b98c94fa111b101aa25c94dbc86aa8776e96048c27cf9d646e9aa2f68f
 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/CommitHook.java a2e60ef94c56b9c5058130eaeadf98e6121d28f1828000e5e998397a0c3dde74
 F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 70dc7bc41f80352ff3d4331e2e24f45fcd23353b3641e2f68a81bd8262215861
 F ext/jni/src/org/sqlite/jni/OutputPointer.java 08a752b58a33696c5eaf0eb9361a0966b188dec40f4a3613eb133123951f6c5f
 F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
 F ext/jni/src/org/sqlite/jni/SQLFunction.java 663a4e479ec65bfbf893586439e12d30b8237898064a22ab64f5658b57315f37
-F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 5d57e46e9d2a1c50d20cbe890908026252068a67ce61dfbb55f23d867dc1d827
-F ext/jni/src/org/sqlite/jni/Tester1.java 69035e38d68ae18d6cc179a82094d9450e6175c973c19969264d48c0e75d6951
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java ca239543968a4fd229322b92925a2754358964be6b1fc4099ff548372db2009e
+F ext/jni/src/org/sqlite/jni/Tester1.java f7144f586b10e7cd42974c7cb067d7e026a0953612a8ca9fcf950b7e6f636bbf
 F ext/jni/src/org/sqlite/jni/Tracer.java c2fe1eba4a76581b93b375a7b95ab1919e5ae60accfb06d6beb067b033e9bae1
 F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
 F ext/jni/src/org/sqlite/jni/sqlite3.java c7d0500c7269882243aafb41425928d094b2fcbdbc2fd1caffc276871cd3fae3
@@ -2067,8 +2068,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 991c66197e4dc7297fce3b20a1b4846873bcd4ce8add36aac71bd2e0e73c207b
-R 3db7b0c753b00fafc33e16210b0ec893
+P 437ecfe8abf8d294d429d191d811da6148e0b2ebb74cf66998480bfc8ef58bdf
+R f8d9020a913f8fd8756147b3f4685626
 U stephan
-Z b93e8aa0e181c83baf410d69abe8fc02
+Z 4f8f049f3a39067bd46eaa81ec3fdaf7
 # Remove this line to create a well-formed Fossil manifest.
index 2fd5dd978abb8579dafc46606db7d1b8a9ac71a0..844332b6b581548bf3c098980202c5ce66f47ff3 100644 (file)
@@ -1 +1 @@
-437ecfe8abf8d294d429d191d811da6148e0b2ebb74cf66998480bfc8ef58bdf
\ No newline at end of file
+c687297fcae082cbd7f9258c43f3841fd34904d8b62b0adf3cd61fcddeee483d
\ No newline at end of file