]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Bind sqlite3_rollback_hook() to JNI.
authorstephan <stephan@noemail.net>
Sun, 30 Jul 2023 06:44:21 +0000 (06:44 +0000)
committerstephan <stephan@noemail.net>
Sun, 30 Jul 2023 06:44:21 +0000 (06:44 +0000)
FossilOrigin-Name: 5f8ee44098d74ac2b98e4dd43ad80d3b919528358b3f992b425af7fa6262dcee

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/c/sqlite3-jni.h
ext/jni/src/org/sqlite/jni/CommitHook.java
ext/jni/src/org/sqlite/jni/RollbackHook.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 9d923a539305b4b1eee624e1b0617bb6dba0ae16..4daa1d104c3db10f82b6b91176e841a8ce818a4d 100644 (file)
@@ -340,6 +340,12 @@ typedef struct {
   jmethodID jmidxCallback /* klazz's xCallback method */;
 } BusyHandlerJni;
 
+typedef struct JniHookState JniHookState;
+struct JniHookState{
+  jobject jObj;
+  jmethodID midCallback;
+};
+
 
 /**
    Per-(sqlite3*) state for bindings which do not have their own
@@ -359,22 +365,10 @@ struct PerDbStateJni {
   sqlite3 * pDb;
   PerDbStateJni * pNext;
   PerDbStateJni * pPrev;
-  struct {
-    jobject jObj;
-    jmethodID midCallback;
-  } trace;
-  struct {
-    jobject jObj;
-    jmethodID midCallback;
-  } progress;
-  struct {
-    jobject jObj;
-    jmethodID midCallback;
-  } commitHook;
-  struct {
-    jobject jObj;
-    jmethodID midCallback;
-  } rollbackHook;
+  JniHookState trace;
+  JniHookState progress;
+  JniHookState commitHook;
+  JniHookState rollbackHook;
   BusyHandlerJni busyHandler;
 };
 
@@ -1512,55 +1506,71 @@ 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;
+
+static int s3jni_commit_rollback_hook_impl(int isCommit, PerDbStateJni * const ps){
   JNIEnv * const env = ps->env;
-  int rc = (int)(*env)->CallIntMethod(env, ps->commitHook.jObj,
-                                      ps->commitHook.midCallback);
+  int rc = isCommit
+    ? (int)(*env)->CallIntMethod(env, ps->commitHook.jObj,
+                                 ps->commitHook.midCallback)
+    : (int)((*env)->CallVoidMethod(env, ps->rollbackHook.jObj,
+                                   ps->rollbackHook.midCallback), 0);
   IFTHREW{
     EXCEPTION_CLEAR;
-    rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
-                        "sqlite3_commit_hook() callback threw.");
+    rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, "hook callback threw.");
   }
   return rc;
 }
 
-JDECL(jobject,1commit_1hook)(JENV_JSELF,jobject jDb, jobject jCommitHook){
+static int s3jni_commit_hook_impl(void *pP){
+  return s3jni_commit_rollback_hook_impl(1, pP);
+}
+
+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 *env,jobject jDb,
+                                          jobject jHook){
   sqlite3 * const pDb = PtrGet_sqlite3(jDb);
-  PerDbStateJni * ps = PerDbStateJni_for_db(env, pDb, 1);
+  PerDbStateJni * const ps = PerDbStateJni_for_db(env, pDb, 1);
   jclass klazz;
   jobject pOld = 0;
   jmethodID xCallback;
+  JniHookState * const pHook = isCommit ? &ps->commitHook : &ps->rollbackHook;
   if(!ps){
     s3jni_db_error(pDb, SQLITE_NOMEM, 0);
     return 0;
   }
-  pOld = ps->commitHook.jObj;
-  if(pOld && jCommitHook &&
-     (*env)->IsSameObject(env, pOld, jCommitHook)){
+  pOld = pHook->jObj;
+  if(pOld && jHook &&
+     (*env)->IsSameObject(env, pOld, jHook)){
     return pOld;
   }
-  if( !jCommitHook ){
+  if( !jHook ){
     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);
+    memset(pHook, 0, sizeof(JniHookState));
+    if( isCommit ) sqlite3_commit_hook(pDb, 0, 0);
+    else sqlite3_rollback_hook(pDb, 0, 0);
     return pOld;
   }
-  klazz = (*env)->GetObjectClass(env, jCommitHook);
-  xCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I");
+  klazz = (*env)->GetObjectClass(env, jHook);
+  xCallback = (*env)->GetMethodID(env, klazz,
+                                  isCommit ? "xCommitHook" : "xRollbackHook",
+                                  isCommit ? "()I" : "()V");
   IFTHREW {
     EXCEPTION_CLEAR;
     s3jni_db_error(pDb, SQLITE_ERROR,
-                   "Cannot not find matching xCallback() on "
-                   "CommitHook object.");
+                   "Cannot not find matching callback on "
+                   "hook object.");
   }else{
-    ps->commitHook.midCallback = xCallback;
-    ps->commitHook.jObj = REF_G(jCommitHook);
-    sqlite3_commit_hook(pDb, s3jni_commit_hook_impl, ps);
+    pHook->midCallback = xCallback;
+    pHook->jObj = REF_G(jHook);
+    if( isCommit ) sqlite3_commit_hook(pDb, s3jni_commit_hook_impl, ps);
+    else sqlite3_rollback_hook(pDb, s3jni_rollback_hook_impl, ps);
     if(pOld){
       jobject tmp = REF_L(pOld);
       UNREF_G(pOld);
@@ -1570,6 +1580,10 @@ JDECL(jobject,1commit_1hook)(JENV_JSELF,jobject jDb, jobject jCommitHook){
   return pOld;
 }
 
+JDECL(jobject,1commit_1hook)(JENV_JSELF,jobject jDb, jobject jHook){
+  return s3jni_commit_rollback_hook(1, env, jDb, jHook);
+}
+
 
 JDECL(jstring,1compileoption_1get)(JENV_JSELF, jint n){
   return (*env)->NewStringUTF( env, sqlite3_compileoption_get(n) );
@@ -2007,6 +2021,9 @@ JDECL(jint,1result_1zeroblob64)(JENV_JSELF, jobject jpCx, jlong v){
   return (jint)sqlite3_result_zeroblob64(PtrGet_sqlite3_context(jpCx), (sqlite3_int64)v);
 }
 
+JDECL(jobject,1rollback_1hook)(JENV_JSELF,jobject jDb, jobject jHook){
+  return s3jni_commit_rollback_hook(0, env, jDb, jHook);
+}
 
 JDECL(void,1set_1last_1insert_1rowid)(JENV_JSELF, jobject jpDb, jlong rowId){
   sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb),
index 11f0f99e9161335c8df74bc20a2feacd857ddb5c..f9fa4a92b1997b2479c9f60c79a5f2d60442eff4 100644 (file)
@@ -1347,6 +1347,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text
 JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64
   (JNIEnv *, jclass, jobject, jbyteArray, jlong, jint);
 
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_rollback_hook
+ * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/RollbackHook;)Lorg/sqlite/jni/RollbackHook;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1rollback_1hook
+  (JNIEnv *, jclass, jobject, jobject);
+
 /*
  * Class:     org_sqlite_jni_SQLite3Jni
  * Method:    sqlite3_set_last_insert_rowid
index c72d2df9b3e99c61363553efc97c6be849ac5425..eaa75a004038c8f1dbe8a14a5029682aac4b5c10 100644 (file)
@@ -21,5 +21,5 @@ public interface CommitHook {
      Works as documented for the sqlite3_commit_hook() callback.
      Must not throw.
   */
-  int xCallback();
+  int xCommitHook();
 }
diff --git a/ext/jni/src/org/sqlite/jni/RollbackHook.java b/ext/jni/src/org/sqlite/jni/RollbackHook.java
new file mode 100644 (file)
index 0000000..4ce3cb9
--- /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_rollback_hook().
+*/
+public interface RollbackHook {
+  /**
+     Works as documented for the sqlite3_rollback_hook() callback.
+     Must not throw.
+  */
+  void xRollbackHook();
+}
index 7bcfb70e8805d985cbff7dd3516ea3db026cf41b..36b824a808d0eed02fa23f1ea163e63d88c7d86e 100644 (file)
@@ -631,7 +631,8 @@ public final class SQLite3Jni {
     sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16BE);
   }
 
-  //TODO void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+  public static native RollbackHook sqlite3_rollback_hook(@NotNull sqlite3 db,
+                                                          @Nullable RollbackHook hook);
 
   public static native void sqlite3_set_last_insert_rowid(@NotNull sqlite3 db, long rowid);
 
index 2c3c6bae8e2b00ef21e32c03f2adf794b220511c..67e3bf639a759475abb3e69bc5d8f148ab41326e 100644 (file)
@@ -756,7 +756,7 @@ public class Tester1 {
     final ValueHolder<Integer> counter = new ValueHolder<>(0);
     final ValueHolder<Integer> hookResult = new ValueHolder<>(0);
     final CommitHook theHook = new CommitHook(){
-        public int xCallback(){
+        public int xCommitHook(){
           ++counter.value;
           return hookResult.value;
         }
@@ -783,7 +783,7 @@ public class Tester1 {
     affirm( 4 == counter.value );
 
     final CommitHook newHook = new CommitHook(){
-        public int xCallback(){return 0;}
+        public int xCommitHook(){return 0;}
       };
     oldHook = sqlite3_commit_hook(db, newHook);
     affirm( null == oldHook );
@@ -800,6 +800,38 @@ public class Tester1 {
     sqlite3_close_v2(db);
   }
 
+  private static void testRollbackHook(){
+    final sqlite3 db = createNewDb();
+    final ValueHolder<Integer> counter = new ValueHolder<>(0);
+    final RollbackHook theHook = new RollbackHook(){
+        public void xRollbackHook(){
+          ++counter.value;
+        }
+      };
+    RollbackHook oldHook = sqlite3_rollback_hook(db, theHook);
+    affirm( null == oldHook );
+    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+    affirm( 0 == counter.value );
+    execSql(db, false, "BEGIN; SELECT 1; SELECT 2; ROLLBACK;");
+    affirm( 1 == counter.value /* contra to commit hook, is invoked if no changes are made */ );
+
+    final RollbackHook newHook = new RollbackHook(){
+        public void xRollbackHook(){return;}
+      };
+    oldHook = sqlite3_rollback_hook(db, newHook);
+    affirm( theHook == oldHook );
+    execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+    affirm( 1 == counter.value );
+    oldHook = sqlite3_rollback_hook(db, theHook);
+    affirm( newHook == oldHook );
+    execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+    affirm( 2 == counter.value );
+    int rc = execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+    affirm( 0 == rc );
+    affirm( 3 == counter.value );
+    sqlite3_close_v2(db);
+  }
+
   private static void testSleep(){
     out("Sleeping briefly... ");
     sqlite3_sleep(600);
@@ -830,6 +862,7 @@ public class Tester1 {
     testBusy();
     testProgress();
     testCommitHook();
+    testRollbackHook();
     //testSleep();
     if(liArgs.indexOf("-v")>0){
       listBoundMethods();
index 974a60d6e5c4a857e159f51f45fb0caa9822618f..d9877eabbff8c31e5b450b64cb09e2fcc1ed77f3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\scommit\shook\sfailure\sto\sJNI\stests.
-D 2023-07-30T06:00:53.315
+C Bind\ssqlite3_rollback_hook()\sto\sJNI.
+D 2023-07-30T06:44:21.370
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -232,17 +232,18 @@ 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 bbc85b4bfe8ea05be23771790824f179b17106a806b2507a6b09c2710483f758
-F ext/jni/src/c/sqlite3-jni.h 2d6ec0b98c94fa111b101aa25c94dbc86aa8776e96048c27cf9d646e9aa2f68f
+F ext/jni/src/c/sqlite3-jni.c 84c082bd07d130b3db4121c32429a9ea1e57c109366b78909b3a7bba4b9afd68
+F ext/jni/src/c/sqlite3-jni.h 58f1f1a363184348c56dd6af47a2311640dde61ab0d9f4ba51fadf6ae5ba88c3
 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/CommitHook.java 87c6a8e5138c61a8eeff018fe16d23f29219150239746032687f245938baca1a
 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/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
 F ext/jni/src/org/sqlite/jni/SQLFunction.java 663a4e479ec65bfbf893586439e12d30b8237898064a22ab64f5658b57315f37
-F ext/jni/src/org/sqlite/jni/SQLite3Jni.java ca239543968a4fd229322b92925a2754358964be6b1fc4099ff548372db2009e
-F ext/jni/src/org/sqlite/jni/Tester1.java 76bca3c7a37019d2631aa224d23edb814c9be322db0529b2fd7cea5d52a202d6
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 1e0ec8a4a5f95b0f595666f9b92246f3394f31f78f62503ed1d1ab879a695101
+F ext/jni/src/org/sqlite/jni/Tester1.java 7d65095d4d4e683f937de57f9340e7eda966a9bd0adba945b86b76570a12c3a7
 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
@@ -2068,8 +2069,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 c687297fcae082cbd7f9258c43f3841fd34904d8b62b0adf3cd61fcddeee483d
-R f495472e9e17ebb6a754de3bf1538a92
+P be4459b495cc2555e4d8ca24dd56c3da1036d25af7cc077bbc3d93c2a3e8c40b
+R 6da75ca1ede9a6d1b13c3955b22a3d72
 U stephan
-Z cadc90f478a05b2b1a81a1b897b5c5ad
+Z 04a18495036c22c78ae28b1e24549558
 # Remove this line to create a well-formed Fossil manifest.
index ff969cfbd78097989a687279aa50b65a329c17bb..5d2b1e08389a36e9616080ef71ad6a125c0d5bc5 100644 (file)
@@ -1 +1 @@
-be4459b495cc2555e4d8ca24dd56c3da1036d25af7cc077bbc3d93c2a3e8c40b
\ No newline at end of file
+5f8ee44098d74ac2b98e4dd43ad80d3b919528358b3f992b425af7fa6262dcee
\ No newline at end of file