From ca379859c9bf10d25f05263d0903e8796250bfe3 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 30 Jul 2023 04:31:56 +0000 Subject: [PATCH] Bind sqlite3_progress_handler() to JNI. Add some metrics to Tester1.java. FossilOrigin-Name: 437ecfe8abf8d294d429d191d811da6148e0b2ebb74cf66998480bfc8ef58bdf --- ext/jni/src/c/sqlite3-jni.c | 67 ++++++++++++++++--- ext/jni/src/c/sqlite3-jni.h | 8 +++ .../src/org/sqlite/jni/ProgressHandler.java | 2 + ext/jni/src/org/sqlite/jni/SQLite3Jni.java | 4 +- ext/jni/src/org/sqlite/jni/Tester1.java | 57 +++++++++++++--- manifest | 20 +++--- manifest.uuid | 2 +- 7 files changed, 125 insertions(+), 35 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 25739904d5..72cfaf209e 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -433,11 +433,11 @@ static void s3jni_free(void * p){ */ static int s3jni_db_error(sqlite3*db, int err_code, const char *zMsg){ if( db!=0 ){ - if( 0!=zMsg ){ + if( 0==zMsg ){ + sqlite3Error(db, err_code); + }else{ const int nMsg = sqlite3Strlen30(zMsg); sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg); - }else{ - sqlite3ErrorWithMsg(db, err_code, NULL); } } return err_code; @@ -526,7 +526,7 @@ static PerDbStateJni * PerDbStateJni_alloc(JNIEnv *env, sqlite3 *pDb){ Clears s's state and moves it to the free-list. */ FIXME_THREADING -static void PerDbStateJni_set_aside(PerDbStateJni *s){ +static void PerDbStateJni_set_aside(PerDbStateJni * const s){ if(s){ JNIEnv * const env = s->env; assert(s->pDb && "Else this object is already in the free-list."); @@ -1726,6 +1726,50 @@ JDECL(jint,1prepare_1v3)(JNIEnv *env, jclass self, jobject jpDb, jbyteArray baSq prepFlags, outStmt, outTail); } + +static int s3jni_progress_handler_impl(void *pP){ + PerDbStateJni * const ps = (PerDbStateJni *)pP; + JNIEnv * const env = ps->env; + int rc = (int)(*env)->CallIntMethod(env, ps->progress.jObj, + ps->progress.midCallback); + IFTHREW{ + EXCEPTION_CLEAR; + rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, + "sqlite3_progress_handler() callback threw."); + } + return rc; +} + +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; + if( n<1 || !jProgress ){ + if(ps){ + UNREF_G(ps->progress.jObj); + memset(&ps->progress, 0, sizeof(ps->progress)); + } + sqlite3_progress_handler(pDb, 0, 0, 0); + return; + } + if(!ps){ + s3jni_db_error(pDb, SQLITE_NOMEM, 0); + return; + } + klazz = (*env)->GetObjectClass(env, jProgress); + ps->progress.midCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I"); + IFTHREW { + EXCEPTION_CLEAR; + s3jni_db_error(pDb, SQLITE_ERROR, + "Cannot not find matching xCallback() on " + "ProgressHandler object."); + }else{ + ps->progress.jObj = REF_G(jProgress); + sqlite3_progress_handler(pDb, (int)n, s3jni_progress_handler_impl, ps); + } +} + + /* sqlite3_result_text/blob() and friends. */ static void result_blob_text(int asBlob, int as64, int eTextRep/*only for (asBlob=0)*/, @@ -1945,30 +1989,31 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){ UNREF_L(jX); IFTHREW{ EXCEPTION_CLEAR; - return rc ? rc : - s3jni_db_error(ps->pDb, SQLITE_ERROR, - "sqlite3_trace_v2() callback threw."); + rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, + "sqlite3_trace_v2() callback threw."); } return rc; } JDECL(jint,1trace_1v2)(JENV_JSELF,jobject jDb, jint traceMask, jobject jTracer){ sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * ps; + PerDbStateJni * const ps = PerDbStateJni_for_db(env, pDb, 1); jclass klazz; if( !traceMask || !jTracer ){ + if(ps){ + UNREF_G(ps->trace.jObj); + memset(&ps->trace, 0, sizeof(ps->trace)); + } return (jint)sqlite3_trace_v2(pDb, 0, 0, 0); } - ps = PerDbStateJni_for_db(env, pDb, 1); if(!ps) return SQLITE_NOMEM; klazz = (*env)->GetObjectClass(env, jTracer); ps->trace.midCallback = (*env)->GetMethodID(env, klazz, "xCallback", "(IJLjava/lang/Object;)I"); IFTHREW { - /* Leave ps in place - it might contain other state. */ EXCEPTION_CLEAR; return s3jni_db_error(pDb, SQLITE_ERROR, - "Cannot not find matchin xCallback() on Tracer object."); + "Cannot not find matching xCallback() on Tracer object."); } ps->trace.jObj = REF_G(jTracer); return sqlite3_trace_v2(pDb, (unsigned)traceMask, s3jni_trace_impl, ps); diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 524a9b4075..739aea7a87 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1195,6 +1195,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v2 JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v3 (JNIEnv *, jclass, jobject, jbyteArray, jint, jint, jobject, jobject); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_progress_handler + * Signature: (Lorg/sqlite/jni/sqlite3;ILorg/sqlite/jni/ProgressHandler;)V + */ +JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1progress_1handler + (JNIEnv *, jclass, jobject, jint, jobject); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_reset diff --git a/ext/jni/src/org/sqlite/jni/ProgressHandler.java b/ext/jni/src/org/sqlite/jni/ProgressHandler.java index b3e8abc0c0..8c463fe364 100644 --- a/ext/jni/src/org/sqlite/jni/ProgressHandler.java +++ b/ext/jni/src/org/sqlite/jni/ProgressHandler.java @@ -18,6 +18,8 @@ package org.sqlite.jni; */ public interface ProgressHandler { /** + Works as documented for the sqlite3_progress_handler() callback. + Must not throw. */ int xCallback(); } diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index eabe1c8609..e3162d7967 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -394,8 +394,8 @@ public final class SQLite3Jni { return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null); } - - //TODO public static native void sqlite3_progress_handler(sqlite3 db, int n, ProgressHandler h); + public static native void sqlite3_progress_handler(@NotNull sqlite3 db, int n, + @Nullable ProgressHandler h); public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt); diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index b2772cc48b..7cc8815436 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -17,6 +17,11 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; public class Tester1 { + private static final class Metrics { + int dbOpen; + } + + static final Metrics metrics = new Metrics(); private static void out(T val){ System.out.print(val); @@ -87,9 +92,10 @@ public class Tester1 { sqlite3 db = new sqlite3(); affirm(0 == db.getNativePointer()); int rc = sqlite3_open(":memory:", db); + ++metrics.dbOpen; affirm(0 == rc); affirm(0 < db.getNativePointer()); - sqlite3_close(db); + sqlite3_close_v2(db); affirm(0 == db.getNativePointer()); } @@ -99,6 +105,7 @@ public class Tester1 { int rc = sqlite3_open_v2(":memory:", db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null); + ++metrics.dbOpen; affirm(0 == rc); affirm(0 < db.getNativePointer()); sqlite3_close_v2(db); @@ -109,6 +116,7 @@ public class Tester1 { sqlite3 db = new sqlite3(); affirm(0 == db.getNativePointer()); int rc = sqlite3_open(":memory:", db); + ++metrics.dbOpen; affirm(0 == rc); affirm(0 != db.getNativePointer()); rc = sqlite3_busy_timeout(db, 2000); @@ -394,7 +402,7 @@ public class Tester1 { affirm(3 == counter); sqlite3_finalize(stmt); affirm(!xDestroyCalled.value); - sqlite3_close(db); + sqlite3_close_v2(db); affirm(xDestroyCalled.value); } @@ -448,7 +456,7 @@ public class Tester1 { execSql(db, "SELECT myfunc(1,2,3)"); affirm(6 == xFuncAccum.value); affirm( !xDestroyCalled.value ); - sqlite3_close(db); + sqlite3_close_v2(db); affirm( xDestroyCalled.value ); } @@ -477,7 +485,7 @@ public class Tester1 { } sqlite3_finalize(stmt); affirm( 1 == n ); - sqlite3_close(db); + sqlite3_close_v2(db); } private static void testUdfAggregate(){ @@ -543,7 +551,7 @@ public class Tester1 { execSql(db, "SELECT myfunc(1) WHERE 0"); affirm(xFinalNull.value); - sqlite3_close(db); + sqlite3_close_v2(db); } private static void testUdfWindow(){ @@ -601,7 +609,7 @@ public class Tester1 { } sqlite3_finalize(stmt); affirm( 5 == n ); - sqlite3_close(db); + sqlite3_close_v2(db); } private static void listBoundMethods(){ @@ -664,7 +672,7 @@ public class Tester1 { }); execSql(db, "SELECT 1; SELECT 2"); affirm( 6 == counter.value ); - sqlite3_close(db); + sqlite3_close_v2(db); affirm( 7 == counter.value ); } @@ -674,9 +682,11 @@ public class Tester1 { final sqlite3 db2 = new sqlite3(); int rc = sqlite3_open(dbName, db1); + ++metrics.dbOpen; affirm( 0 == rc ); execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)"); rc = sqlite3_open(dbName, db2); + ++metrics.dbOpen; affirm( 0 == rc ); final ValueHolder xDestroyed = new ValueHolder<>(false); @@ -701,9 +711,9 @@ public class Tester1 { affirm( SQLITE_BUSY == rc); affirm( 3 == xBusyCalled.value ); sqlite3_finalize(stmt); - sqlite3_close(db1); + sqlite3_close_v2(db1); affirm(!xDestroyed.value); - sqlite3_close(db2); + sqlite3_close_v2(db2); affirm(xDestroyed.value); try{ final java.io.File f = new java.io.File(dbName); @@ -713,6 +723,24 @@ public class Tester1 { } } + private static void testProgress(){ + final sqlite3 db = createNewDb(); + final ValueHolder counter = new ValueHolder<>(0); + sqlite3_progress_handler(db, 1, new ProgressHandler(){ + public int xCallback(){ + ++counter.value; + return 0; + } + }); + execSql(db, "SELECT 1; SELECT 2;"); + affirm( counter.value > 0 ); + int nOld = counter.value; + sqlite3_progress_handler(db, 0, null); + execSql(db, "SELECT 1; SELECT 2;"); + affirm( nOld == counter.value ); + sqlite3_close_v2(db); + } + private static void testSleep(){ out("Sleeping briefly... "); sqlite3_sleep(600); @@ -720,6 +748,7 @@ public class Tester1 { } public static void main(String[] args){ + final long timeStart = System.nanoTime(); test1(); if(false) testCompileOption(); final java.util.List liArgs = @@ -740,10 +769,16 @@ public class Tester1 { testUdfWindow(); testTrace(); testBusy(); - testSleep(); + testProgress(); + //testSleep(); if(liArgs.indexOf("-v")>0){ listBoundMethods(); } - outln("Tests done. "+affirmCount+" assertion checked."); + final long timeEnd = System.nanoTime(); + outln("Tests done. Metrics:"); + outln("\tAssertions checked: "+affirmCount); + outln("\tDatabases opened: "+metrics.dbOpen); + outln("\tTotal time = " + +((timeEnd - timeStart)/1000000.0)+"ms"); } } diff --git a/manifest b/manifest index 1d9b4e8b26..0ccad35a87 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Internal\sJNI\sbinding\sdocs. -D 2023-07-28T18:44:11.596 +C Bind\ssqlite3_progress_handler()\sto\sJNI.\sAdd\ssome\smetrics\sto\sTester1.java. +D 2023-07-30T04:31:56.673 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,16 +232,16 @@ 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 f7f4934cb2698c674842974c1b47d0cba0927ebc5781b0c15304b7ed6c46b743 -F ext/jni/src/c/sqlite3-jni.h c9bb150a38dce09cc2794d5aac8fa097288d9946fbb15250fd0a23c31957f506 +F ext/jni/src/c/sqlite3-jni.c 53fa705d417ab61f4879566352bd1b3e31996aa01d657d6beca597734bff1d0e +F ext/jni/src/c/sqlite3-jni.h 212c3aede7c9ca8b1116a5d822cb89b95b3d7912452dbe778a9fd6cb869607e3 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/NativePointerHolder.java 70dc7bc41f80352ff3d4331e2e24f45fcd23353b3641e2f68a81bd8262215861 F ext/jni/src/org/sqlite/jni/OutputPointer.java 08a752b58a33696c5eaf0eb9361a0966b188dec40f4a3613eb133123951f6c5f -F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5a1d7b2607eb2ef596fcf4492a49d1b3a5bdea3af9918e11716831ffd2f02284 +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 f7939d75d26481d02ea3418fa24bb6f6ba89b98a3e10ac4ab67b7186f9cb4fda -F ext/jni/src/org/sqlite/jni/Tester1.java 6c819172137bf06d76f26df20c4c846abc82523db62c51cc043ac66031298103 +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/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 +2067,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 bcefa2df563260933c7ab5df90872580f71010c11419f6b1de7b1e2747237ff8 -R 934bdd7c3796e2624766f5d43e958073 +P 991c66197e4dc7297fce3b20a1b4846873bcd4ce8add36aac71bd2e0e73c207b +R 3db7b0c753b00fafc33e16210b0ec893 U stephan -Z 1f7372379f92cca45c2da16bb8bc1a04 +Z b93e8aa0e181c83baf410d69abe8fc02 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index edc4bc0e92..2fd5dd978a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -991c66197e4dc7297fce3b20a1b4846873bcd4ce8add36aac71bd2e0e73c207b \ No newline at end of file +437ecfe8abf8d294d429d191d811da6148e0b2ebb74cf66998480bfc8ef58bdf \ No newline at end of file -- 2.47.2