From aad6808efc0b93d914ef156f976dd4b555e27e68 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 12:53:00 +0000 Subject: [PATCH 01/55] Bind the trace API to the JNI wrapper1 API and add a way to map the native-level db/stmt types to their high-level counterparts (required for translating callbacks such as tracers). FossilOrigin-Name: 702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3 --- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 11 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 111 +++++++++++++++++- .../src/org/sqlite/jni/wrapper1/Tester2.java | 58 ++++++++- manifest | 19 ++- manifest.uuid | 2 +- 5 files changed, 180 insertions(+), 21 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 4657185658..a0445adb3a 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -46,7 +46,7 @@ public class Tester1 implements Runnable { //! True to shuffle the order of the tests. private static boolean shuffle = false; //! True to dump the list of to-run tests to stdout. - private static boolean listRunTests = false; + private static int listRunTests = 0; //! True to squelch all out() and outln() output. private static boolean quietMode = false; //! Total number of runTests() calls. @@ -1701,7 +1701,7 @@ public class Tester1 implements Runnable { mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) ); java.util.Collections.shuffle(mlist); } - if( listRunTests ){ + if( (!fromThread && listRunTests>0) || listRunTests>1 ){ synchronized(this.getClass()){ if( !fromThread ){ out("Initial test"," list: "); @@ -1763,8 +1763,11 @@ public class Tester1 implements Runnable { -naps: sleep small random intervals between tests in order to add some chaos for cross-thread contention. + -list-tests: outputs the list of tests being run, minus some - which are hard-coded. This is noisy in multi-threaded mode. + which are hard-coded. In multi-threaded mode, use this twice to + to emit the list run by each thread (which may differ from the initial + list, in particular if -shuffle is used). -fail: forces an exception to be thrown during the test run. Use with -shuffle to make its appearance unpredictable. @@ -1793,7 +1796,7 @@ public class Tester1 implements Runnable { }else if(arg.equals("shuffle")){ shuffle = true; }else if(arg.equals("list-tests")){ - listRunTests = true; + ++listRunTests; }else if(arg.equals("fail")){ forceFail = true; }else if(arg.equals("sqllog")){ diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 907755d99a..685e8c326c 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -61,11 +61,31 @@ public final class Sqlite implements AutoCloseable { public static final int PREPARE_NORMALIZE = CApi.SQLITE_PREPARE_NORMALIZE; public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB; + public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT; + public static final int TRACE_PROFILE = CApi.SQLITE_TRACE_PROFILE; + public static final int TRACE_ROW = CApi.SQLITE_TRACE_ROW; + public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE; + public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE; + //! Used only by the open() factory functions. private Sqlite(sqlite3 db){ this.db = db; } + /** Maps org.sqlite.jni.capi.sqlite3 to Sqlite instances. */ + private static final java.util.Map nativeToWrapper + = new java.util.HashMap<>(); + + /** + Returns the Sqlite object associated with the given sqlite3 + object, or null if there is no such mapping. + */ + static Sqlite fromNative(sqlite3 low){ + synchronized(nativeToWrapper){ + return nativeToWrapper.get(low); + } + } + /** Returns a newly-opened db connection or throws SqliteException if opening fails. All arguments are as documented for @@ -84,7 +104,11 @@ public final class Sqlite implements AutoCloseable { n.close(); throw ex; } - return new Sqlite(n); + Sqlite rv = new Sqlite(n); + synchronized(nativeToWrapper){ + nativeToWrapper.put(n, rv); + } + return rv; } public static Sqlite open(String filename, int flags){ @@ -124,6 +148,9 @@ public final class Sqlite implements AutoCloseable { @Override public void close(){ if(null!=this.db){ + synchronized(nativeToWrapper){ + nativeToWrapper.remove(this.db); + } this.db.close(); this.db = null; } @@ -467,11 +494,71 @@ public final class Sqlite implements AutoCloseable { return rv; } + public interface TraceCallback { + /** + Called by sqlite3 for various tracing operations, as per + sqlite3_trace_v2(). Note that this interface elides the 2nd + argument to the native trace callback, as that role is better + filled by instance-local state. + +

These callbacks may throw, in which case their exceptions are + converted to C-level error information. + +

The 2nd argument to this function, if non-null, will be a an + Sqlite or Sqlite.Stmt object, depending on the first argument + (see below). + +

The final argument to this function is the "X" argument + documented for sqlite3_trace() and sqlite3_trace_v2(). Its type + depends on value of the first argument: + +

- SQLITE_TRACE_STMT: pNative is a Sqlite.Stmt. pX is a String + containing the prepared SQL. + +

- SQLITE_TRACE_PROFILE: pNative is a sqlite3_stmt. pX is a Long + holding an approximate number of nanoseconds the statement took + to run. + +

- SQLITE_TRACE_ROW: pNative is a sqlite3_stmt. pX is null. + +

- SQLITE_TRACE_CLOSE: pNative is a sqlite3. pX is null. + */ + void call(int traceFlag, Object pNative, Object pX); + } + + /** + Analog to sqlite3_trace_v2(). traceMask must be a mask of the + TRACE_... constants. Pass a null callback to remove tracing. + + Throws on error. + */ + public void trace(int traceMask, TraceCallback callback){ + final Sqlite self = this; + final org.sqlite.jni.capi.TraceV2Callback tc = + (null==callback) ? null : new org.sqlite.jni.capi.TraceV2Callback(){ + @SuppressWarnings("unchecked") + @Override public int call(int flag, Object pNative, Object pX){ + switch(flag){ + case TRACE_ROW: + case TRACE_PROFILE: + case TRACE_STMT: + callback.call(flag, Sqlite.Stmt.fromNative((sqlite3_stmt)pNative), pX); + break; + case TRACE_CLOSE: + callback.call(flag, self, pX); + break; + } + return 0; + } + }; + checkRc( CApi.sqlite3_trace_v2(thisDb(), traceMask, tc) ); + }; + /** Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to create new instances. */ - public final class Stmt implements AutoCloseable { + public static final class Stmt implements AutoCloseable { private Sqlite _db = null; private sqlite3_stmt stmt = null; /** @@ -489,12 +576,29 @@ public final class Sqlite implements AutoCloseable { this._db = db; this.stmt = stmt; this.resultColCount = CApi.sqlite3_column_count(stmt); + synchronized(nativeToWrapper){ + nativeToWrapper.put(this.stmt, this); + } } sqlite3_stmt nativeHandle(){ return stmt; } + /** Maps org.sqlite.jni.capi.sqlite3_stmt to Stmt instances. */ + private static final java.util.Map nativeToWrapper + = new java.util.HashMap<>(); + + /** + Returns the Stmt object associated with the given sqlite3_stmt + object, or null if there is no such mapping. + */ + static Stmt fromNative(sqlite3_stmt low){ + synchronized(nativeToWrapper){ + return nativeToWrapper.get(low); + } + } + /** If this statement is still opened, its low-level handle is returned, eelse an IllegalArgumentException is thrown. @@ -527,6 +631,9 @@ public final class Sqlite implements AutoCloseable { public int finalizeStmt(){ int rc = 0; if( null!=stmt ){ + synchronized(nativeToWrapper){ + nativeToWrapper.remove(this.stmt); + } sqlite3_finalize(stmt); stmt = null; _db = null; diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index d24551ebf1..b6f1011489 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -46,7 +46,7 @@ public class Tester2 implements Runnable { //! True to shuffle the order of the tests. private static boolean shuffle = false; //! True to dump the list of to-run tests to stdout. - private static boolean listRunTests = false; + private static int listRunTests = 0; //! True to squelch all out() and outln() output. private static boolean quietMode = false; //! Total number of runTests() calls. @@ -444,6 +444,54 @@ public class Tester2 implements Runnable { db.close(); } + + private void testTrace(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + /* Ensure that characters outside of the UTF BMP survive the trip + from Java to sqlite3 and back to Java. (At no small efficiency + penalty.) */ + final String nonBmpChar = "😃"; + db.trace( + Sqlite.TRACE_ALL, + new Sqlite.TraceCallback(){ + @Override public void call(int traceFlag, Object pNative, Object x){ + ++counter.value; + //outln("TRACE "+traceFlag+" pNative = "+pNative.getClass().getName()); + switch(traceFlag){ + case Sqlite.TRACE_STMT: + affirm(pNative instanceof Sqlite.Stmt); + //outln("TRACE_STMT sql = "+x); + affirm(x instanceof String); + affirm( ((String)x).indexOf(nonBmpChar) > 0 ); + break; + case Sqlite.TRACE_PROFILE: + affirm(pNative instanceof Sqlite.Stmt); + affirm(x instanceof Long); + //outln("TRACE_PROFILE time = "+x); + break; + case Sqlite.TRACE_ROW: + affirm(pNative instanceof Sqlite.Stmt); + affirm(null == x); + //outln("TRACE_ROW = "+sqlite3_column_text16((sqlite3_stmt)pNative, 0)); + break; + case Sqlite.TRACE_CLOSE: + affirm(pNative instanceof Sqlite); + affirm(null == x); + break; + default: + affirm(false /*cannot happen*/); + break; + } + } + }); + execSql(db, "SELECT coalesce(null,null,'"+nonBmpChar+"'); "+ + "SELECT 'w"+nonBmpChar+"orld'"); + affirm( 6 == counter.value ); + db.close(); + affirm( 7 == counter.value ); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); @@ -451,7 +499,7 @@ public class Tester2 implements Runnable { mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) ); java.util.Collections.shuffle(mlist); } - if( listRunTests ){ + if( (!fromThread && listRunTests>0) || listRunTests>1 ){ synchronized(this.getClass()){ if( !fromThread ){ out("Initial test"," list: "); @@ -514,7 +562,9 @@ public class Tester2 implements Runnable { some chaos for cross-thread contention. -list-tests: outputs the list of tests being run, minus some - which are hard-coded. This is noisy in multi-threaded mode. + which are hard-coded. In multi-threaded mode, use this twice to + to emit the list run by each thread (which may differ from the initial + list, in particular if -shuffle is used). -fail: forces an exception to be thrown during the test run. Use with -shuffle to make its appearance unpredictable. @@ -543,7 +593,7 @@ public class Tester2 implements Runnable { }else if(arg.equals("shuffle")){ shuffle = true; }else if(arg.equals("list-tests")){ - listRunTests = true; + ++listRunTests; }else if(arg.equals("fail")){ forceFail = true; }else if(arg.equals("sqllog")){ diff --git a/manifest b/manifest index 18d8f5e182..ae3068b124 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Back\sout\sthe\sALWAYS\sinserted\slate\syesterday.\s\sThe\sfuzzer\sdiscovered\sa\ncounter-example. -D 2023-11-03T18:45:26.322 +C Bind\sthe\strace\sAPI\sto\sthe\sJNI\swrapper1\sAPI\sand\sadd\sa\sway\sto\smap\sthe\snative-level\sdb/stmt\stypes\sto\stheir\shigh-level\scounterparts\s(required\sfor\stranslating\scallbacks\ssuch\sas\stracers). +D 2023-11-04T12:53:00.737 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java b6b2f3354ba68956a6bcd1c586b8eb25a0bd66eed2b58b340405e1129da15de9 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java fba87e2c39ba186bb7add972d9e84b7f817f656452cf4f317679575bd5a738e7 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 0b01b9058ef6737c85b505c6aa2490fb1dc1d974fb39d88a93269fed09553f9f -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 1c95f5e0f872aeb9cdd174cbb2e254d158df1f8b2fee9f0e6ec82c348602a7bd +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 12a9323a74e38e7c6229dc73c5b62bf50088a65310100f383469308549381907 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 9ab7e38e6741842f8e3b74cd3ecb4953e2f1957f5229bd32663df7331245ce95 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 83cfe6583c8df226eda985eed059f47efaefaca3951c618c286ffc8c63210ee8 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java 1a1afbafbd7406ff67e7d6405541c6347517c731de535a97d7a3df1d4db835b4 F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,9 +2142,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 8f5e9c192ff2820d8cfb076ab28f30697d10c22710583d6c7fd7019c4a0ea795 -Q -268b5984a4263bee245a9bb47ac927bde56cdf4af8795b851dada5622224076f -R 4994e654abc4ea7988499736bdf83ad0 -U drh -Z 5983c90319f7844a8c9e3e4e981877ce +P 570635575cc5fbffe910ed992b58393e214117ef3b5370a66f115cd0ee202913 +R cb275d62547ff275bdfb4b29d97a5241 +U stephan +Z 2824e678eb263c5ade76d9ba9fb58525 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f69aa3731a..0e828aa55c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -570635575cc5fbffe910ed992b58393e214117ef3b5370a66f115cd0ee202913 \ No newline at end of file +702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3 \ No newline at end of file From 5f3b13d1367f13e8f70d85522228c71c33cf1fd9 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 13:16:49 +0000 Subject: [PATCH 02/55] Bind the bool-flag sqlite3_db_config() variants to the JNI wrapper1 API. FossilOrigin-Name: b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921 --- ext/jni/src/c/sqlite3-jni.c | 1 - ext/jni/src/org/sqlite/jni/capi/CApi.java | 3 +- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 1 + .../src/org/sqlite/jni/wrapper1/Sqlite.java | 32 +++++++++++++++++++ .../src/org/sqlite/jni/wrapper1/Tester2.java | 21 ++++++++---- manifest | 20 ++++++------ manifest.uuid | 2 +- 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 6d54391e18..e6b0750cbd 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -3429,7 +3429,6 @@ S3JniApi( } break; } - case 0: default: rc = SQLITE_MISUSE; } diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 6eeeb29a24..ef1ca17b22 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -828,7 +828,7 @@ public final class CApi { SQLITE_DBCONFIG_... options which uses this call form.

Unlike the C API, this returns SQLITE_MISUSE if its db argument - are null (as opposed to invoking UB). + is null (as opposed to invoking UB). */ public static native int sqlite3_db_config( @NotNull sqlite3 db, int op, int onOff, @Nullable OutputPointer.Int32 out @@ -851,7 +851,6 @@ public final class CApi { return null==db ? null : sqlite3_db_name(db.getNativePointer(), ndx); } - public static native String sqlite3_db_filename( @NotNull sqlite3 db, @NotNull String dbName ); diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index a0445adb3a..fdadb3e29d 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1049,6 +1049,7 @@ public class Tester1 implements Runnable { rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo"); affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) ); affirm( "foo".equals( sqlite3_db_name(db1, 0) ) ); + affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) ); final ValueHolder xBusyCalled = new ValueHolder<>(0); BusyHandlerCallback handler = new BusyHandlerCallback(){ diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 685e8c326c..3e24f52f33 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -67,6 +67,25 @@ public final class Sqlite implements AutoCloseable { public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE; public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE; + public static final int DBCONFIG_ENABLE_FKEY = CApi.SQLITE_DBCONFIG_ENABLE_FKEY; + public static final int DBCONFIG_ENABLE_TRIGGER = CApi.SQLITE_DBCONFIG_ENABLE_TRIGGER; + public static final int DBCONFIG_ENABLE_FTS3_TOKENIZER = CApi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER; + public static final int DBCONFIG_ENABLE_LOAD_EXTENSION = CApi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION; + public static final int DBCONFIG_NO_CKPT_ON_CLOSE = CApi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE; + public static final int DBCONFIG_ENABLE_QPSG = CApi.SQLITE_DBCONFIG_ENABLE_QPSG; + public static final int DBCONFIG_TRIGGER_EQP = CApi.SQLITE_DBCONFIG_TRIGGER_EQP; + public static final int DBCONFIG_RESET_DATABASE = CApi.SQLITE_DBCONFIG_RESET_DATABASE; + public static final int DBCONFIG_DEFENSIVE = CApi.SQLITE_DBCONFIG_DEFENSIVE; + public static final int DBCONFIG_WRITABLE_SCHEMA = CApi.SQLITE_DBCONFIG_WRITABLE_SCHEMA; + public static final int DBCONFIG_LEGACY_ALTER_TABLE = CApi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE; + public static final int DBCONFIG_DQS_DML = CApi.SQLITE_DBCONFIG_DQS_DML; + public static final int DBCONFIG_DQS_DDL = CApi.SQLITE_DBCONFIG_DQS_DDL; + public static final int DBCONFIG_ENABLE_VIEW = CApi.SQLITE_DBCONFIG_ENABLE_VIEW; + public static final int DBCONFIG_LEGACY_FILE_FORMAT = CApi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT; + public static final int DBCONFIG_TRUSTED_SCHEMA = CApi.SQLITE_DBCONFIG_TRUSTED_SCHEMA; + public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS; + public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER; + //! Used only by the open() factory functions. private Sqlite(sqlite3 db){ this.db = db; @@ -375,6 +394,19 @@ public final class Sqlite implements AutoCloseable { return CApi.sqlite3_db_filename(thisDb(), dbName); } + /** + Analog to sqlite3_db_config() for the call forms which take one + of the boolean-type db configuration flags (namely the + DBCONFIG_... constants defined in this class). On success it + returns the result of that underlying call. Throws on error. + */ + public boolean dbConfig(int op, boolean on){ + org.sqlite.jni.capi.OutputPointer.Int32 pOut = + new org.sqlite.jni.capi.OutputPointer.Int32(); + checkRc( CApi.sqlite3_db_config(thisDb(), op, on ? 1 : 0, pOut) ); + return pOut.get()!=0; + } + /** Analog to the variant of sqlite3_db_config() for configuring the SQLITE_DBCONFIG_MAINDBNAME option. Throws on error. diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index b6f1011489..38bcb54c66 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -211,15 +211,24 @@ public class Tester2 implements Runnable { void testOpenDb1(){ Sqlite db = openDb(); affirm( 0!=db.nativeHandle().getNativePointer() ); + affirm( "main".equals( db.dbName(0) ) ); + db.setMainDbName("foo"); + affirm( "foo".equals( db.dbName(0) ) ); + affirm( db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, true) + /* The underlying function has different mangled names in jdk8 + vs jdk19, and this call is here to ensure that the build + fails if it cannot find both names. */ ); + affirm( !db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, false) ); + SqliteException ex = null; + try{ db.dbConfig(0, false); } + catch(SqliteException e){ ex = e; } + affirm( null!=ex ); + ex = null; db.close(); affirm( null==db.nativeHandle() ); - SqliteException ex = null; - try { - db = openDb("/no/such/dir/.../probably"); - }catch(SqliteException e){ - ex = e; - } + try{ db = openDb("/no/such/dir/.../probably"); } + catch(SqliteException e){ ex = e; } affirm( ex!=null ); affirm( ex.errcode() != 0 ); affirm( ex.extendedErrcode() != 0 ); diff --git a/manifest b/manifest index ae3068b124..cbf52bf2f6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\sthe\strace\sAPI\sto\sthe\sJNI\swrapper1\sAPI\sand\sadd\sa\sway\sto\smap\sthe\snative-level\sdb/stmt\stypes\sto\stheir\shigh-level\scounterparts\s(required\sfor\stranslating\scallbacks\ssuch\sas\stracers). -D 2023-11-04T12:53:00.737 +C Bind\sthe\sbool-flag\ssqlite3_db_config()\svariants\sto\sthe\sJNI\swrapper1\sAPI. +D 2023-11-04T13:16:49.628 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c afe9c25b82279a28fe2c81f869070fa0d434b0a8ccd7f8aca0e8173db410d14a +F ext/jni/src/c/sqlite3-jni.c 53493819418048bfdc8e6f505954c7e692d4666b64c3ae732ea8319c91aac747 F ext/jni/src/c/sqlite3-jni.h 1c45fd4689cec42f3d84d2fee41bb494016a12fcb5fd80291095590666a14015 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 24aba7b14b11da52cd47083608d37c186122c2e2072e75b2ff923d1f15bfb9e5 +F ext/jni/src/org/sqlite/jni/capi/CApi.java d21e6c1c4557ae18bbc2eefb0882efdb36fdaecdc58823c142def994327a365b F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java fba87e2c39ba186bb7add972d9e84b7f817f656452cf4f317679575bd5a738e7 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 41e2b910a11dfdd4cc39ab608492d7c12f3791e85ac7f9d75d5445f7645a5e57 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 0b01b9058ef6737c85b505c6aa2490fb1dc1d974fb39d88a93269fed09553f9f -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 12a9323a74e38e7c6229dc73c5b62bf50088a65310100f383469308549381907 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0033898c318eea50489817957ef6078064f2b70b2838733462663ca3d6b09127 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 83cfe6583c8df226eda985eed059f47efaefaca3951c618c286ffc8c63210ee8 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 00c697a57af398d6c49b2c32c10314201a5d0fa0862dc496f9d4f2139087b76b F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java 1a1afbafbd7406ff67e7d6405541c6347517c731de535a97d7a3df1d4db835b4 F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 570635575cc5fbffe910ed992b58393e214117ef3b5370a66f115cd0ee202913 -R cb275d62547ff275bdfb4b29d97a5241 +P 702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3 +R 86eeaee301f846f2f1ea6341b6a33699 U stephan -Z 2824e678eb263c5ade76d9ba9fb58525 +Z e6b3bd265a1978cd37eafbdc1dc5ccf4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0e828aa55c..3c3ee0a4df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3 \ No newline at end of file +b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921 \ No newline at end of file From 348e192ea896293e704afb1b8cc323fa85dba293 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 13:37:42 +0000 Subject: [PATCH 03/55] Rework the JNI wrapper1 variants of status() and db_status() to be more Java-esque. FossilOrigin-Name: 40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8 --- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 70 +++++++++++++++++-- .../src/org/sqlite/jni/wrapper1/Tester2.java | 15 ++++ manifest | 14 ++-- manifest.uuid | 2 +- 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 3e24f52f33..0ea2c38768 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -44,6 +44,20 @@ public final class Sqlite implements AutoCloseable { public static final int STATUS_PAGECACHE_SIZE = CApi.SQLITE_STATUS_PAGECACHE_SIZE; public static final int STATUS_MALLOC_COUNT = CApi.SQLITE_STATUS_MALLOC_COUNT; + public static final int DBSTATUS_LOOKASIDE_USED = CApi.SQLITE_DBSTATUS_LOOKASIDE_USED; + public static final int DBSTATUS_CACHE_USED = CApi.SQLITE_DBSTATUS_CACHE_USED; + public static final int DBSTATUS_SCHEMA_USED = CApi.SQLITE_DBSTATUS_SCHEMA_USED; + public static final int DBSTATUS_STMT_USED = CApi.SQLITE_DBSTATUS_STMT_USED; + public static final int DBSTATUS_LOOKASIDE_HIT = CApi.SQLITE_DBSTATUS_LOOKASIDE_HIT; + public static final int DBSTATUS_LOOKASIDE_MISS_SIZE = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE; + public static final int DBSTATUS_LOOKASIDE_MISS_FULL = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL; + public static final int DBSTATUS_CACHE_HIT = CApi.SQLITE_DBSTATUS_CACHE_HIT; + public static final int DBSTATUS_CACHE_MISS = CApi.SQLITE_DBSTATUS_CACHE_MISS; + public static final int DBSTATUS_CACHE_WRITE = CApi.SQLITE_DBSTATUS_CACHE_WRITE; + public static final int DBSTATUS_DEFERRED_FKS = CApi.SQLITE_DBSTATUS_DEFERRED_FKS; + public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED; + public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL; + public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH; public static final int LIMIT_SQL_LENGTH = CApi.SQLITE_LIMIT_SQL_LENGTH; public static final int LIMIT_COLUMN = CApi.SQLITE_LIMIT_COLUMN; @@ -150,19 +164,49 @@ public final class Sqlite implements AutoCloseable { return CApi.sqlite3_sourceid(); } + + /** + Output object for use with status() and libStatus(). + */ + public static final class Status { + /** The current value for the requested status() or libStatus() metric. */ + long current; + /** The peak value for the requested status() or libStatus() metric. */ + long peak; + }; + /** As per sqlite3_status64(), but returns its current and high-water - results as a two-element array. Throws if the first argument is + results as a Status object. Throws if the first argument is not one of the STATUS_... constants. */ - public long[] libStatus(int op, boolean resetStats){ + public static Status libStatus(int op, boolean resetStats){ org.sqlite.jni.capi.OutputPointer.Int64 pCurrent = new org.sqlite.jni.capi.OutputPointer.Int64(); org.sqlite.jni.capi.OutputPointer.Int64 pHighwater = new org.sqlite.jni.capi.OutputPointer.Int64(); - final int rc = CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats); - checkRc(rc); - return new long[] {pCurrent.value, pHighwater.value}; + checkRc2( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) ); + final Status s = new Status(); + s.current = pCurrent.value; + s.peak = pHighwater.value; + return s; + } + + /** + As per sqlite3_status64(), but returns its current and high-water + results as a Status object. Throws if the first argument is + not one of the DBSTATUS_... constants or on any other misuse. + */ + public Status status(int op, boolean resetStats){ + org.sqlite.jni.capi.OutputPointer.Int32 pCurrent = + new org.sqlite.jni.capi.OutputPointer.Int32(); + org.sqlite.jni.capi.OutputPointer.Int32 pHighwater = + new org.sqlite.jni.capi.OutputPointer.Int32(); + checkRc( CApi.sqlite3_db_status(thisDb(), op, pCurrent, pHighwater, resetStats) ); + final Status s = new Status(); + s.current = pCurrent.value; + s.peak = pHighwater.value; + return s; } @Override public void close(){ @@ -272,6 +316,20 @@ public final class Sqlite implements AutoCloseable { } } + /** + Like checkRc() but behaves as if that function were + called with a null db object. + */ + private static void checkRc2(int rc){ + if( 0!=rc ){ + if( CApi.SQLITE_NOMEM==rc ){ + throw new OutOfMemoryError(); + }else{ + throw new SqliteException(rc); + } + } + } + /** prepFlags must be 0 or a bitmask of the PREPARE_... constants. @@ -440,7 +498,7 @@ public final class Sqlite implements AutoCloseable { /** Analog to sqlite3_release_memory(). */ - public static int releaseMemory(int n){ + public static int libReleaseMemory(int n){ return CApi.sqlite3_release_memory(n); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 38bcb54c66..b83cd44601 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -501,6 +501,21 @@ public class Tester2 implements Runnable { affirm( 7 == counter.value ); } + private void testStatus(){ + final Sqlite db = openDb(); + execSql(db, "create table t(a); insert into t values(1),(2),(3)"); + + Sqlite.Status s = Sqlite.libStatus(Sqlite.STATUS_MEMORY_USED, false); + affirm( s.current > 0 ); + affirm( s.peak >= s.current ); + + s = db.status(Sqlite.DBSTATUS_SCHEMA_USED, false); + affirm( s.current > 0 ); + affirm( s.peak == 0 /* always 0 for SCHEMA_USED */ ); + + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index cbf52bf2f6..5ee7dad393 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\sthe\sbool-flag\ssqlite3_db_config()\svariants\sto\sthe\sJNI\swrapper1\sAPI. -D 2023-11-04T13:16:49.628 +C Rework\sthe\sJNI\swrapper1\svariants\sof\sstatus()\sand\sdb_status()\sto\sbe\smore\sJava-esque. +D 2023-11-04T13:37:42.589 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 0b01b9058ef6737c85b505c6aa2490fb1dc1d974fb39d88a93269fed09553f9f -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0033898c318eea50489817957ef6078064f2b70b2838733462663ca3d6b09127 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java ab6bee53895e5f7345b57d32ef30e9cc9c9c09979a31211f63e60dcdea9a7ab1 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 00c697a57af398d6c49b2c32c10314201a5d0fa0862dc496f9d4f2139087b76b +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java cbd087d3fcbfca384656fc2189a9b017e4afe70f0f17d8266d28c628ab97cada F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java 1a1afbafbd7406ff67e7d6405541c6347517c731de535a97d7a3df1d4db835b4 F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3 -R 86eeaee301f846f2f1ea6341b6a33699 +P b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921 +R 9ee74b8e162e4e8a23028ccec92c6373 U stephan -Z e6b3bd265a1978cd37eafbdc1dc5ccf4 +Z ce3f2fb1a954c596b6cdbc560de71d23 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3c3ee0a4df..18ae81abac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921 \ No newline at end of file +40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8 \ No newline at end of file From 1b199243cbff71e3e60caf9d7cb2be0f76eb894f Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 16:01:13 +0000 Subject: [PATCH 04/55] Expose context_db_handle() to the JNI wrapper1 API and clean up some related tests. FossilOrigin-Name: c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566 --- .../jni/wrapper1/AggregateFunction.java | 4 ---- .../org/sqlite/jni/wrapper1/SqlFunction.java | 12 +++++++++- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 2 +- .../sqlite/jni/wrapper1/SqliteException.java | 2 +- .../src/org/sqlite/jni/wrapper1/Tester2.java | 18 +++++++++++---- .../sqlite/jni/wrapper1/WindowFunction.java | 4 ---- manifest | 22 +++++++++---------- manifest.uuid | 2 +- 8 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java index 6a38d4b530..fc63b53542 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java @@ -12,10 +12,6 @@ ** This file is part of the wrapper1 interface for sqlite3. */ package org.sqlite.jni.wrapper1; -import org.sqlite.jni.capi.CApi; -import org.sqlite.jni.annotation.*; -import org.sqlite.jni.capi.sqlite3_context; -import org.sqlite.jni.capi.sqlite3_value; /** EXPERIMENTAL/INCOMPLETE/UNTESTED diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index 5bcb3bd5fa..941800513d 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -56,7 +56,7 @@ public interface SqlFunction { */ Arguments(sqlite3_context cx, sqlite3_value args[]){ this.cx = cx; - this.args = args==null ? new sqlite3_value[0] : args;; + this.args = args==null ? new sqlite3_value[0] : args; this.length = this.args.length; } @@ -76,6 +76,16 @@ public interface SqlFunction { //! Returns the underlying sqlite3_context for these arguments. sqlite3_context getContext(){return cx;} + /** + Returns the Sqlite (db) object associated with this UDF call, + or null if the UDF is somehow called without such an object or + the db has been closed in an untimely manner (e.g. closed by a + UDF call). + */ + public Sqlite getDb(){ + return Sqlite.fromNative( CApi.sqlite3_context_db_handle(cx) ); + } + public int getArgCount(){ return args.length; } public int getInt(int argNdx){return CApi.sqlite3_value_int(valueAt(argNdx));} diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 0ea2c38768..4f14253a3e 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -781,7 +781,7 @@ public final class Sqlite implements AutoCloseable { Returns the Sqlite which prepared this statement, or null if this statement has been finalized. */ - public Sqlite db(){ return this._db; } + public Sqlite getDb(){ return this._db; } /** Works like sqlite3_reset() but throws on error. diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java index 27cfc0e6bb..09fa02a2ca 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java @@ -74,7 +74,7 @@ public final class SqliteException extends java.lang.RuntimeException { } public SqliteException(Sqlite.Stmt stmt){ - this(stmt.db()); + this(stmt.getDb()); } public int errcode(){ return errCode; } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index b83cd44601..5f991da4d3 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -241,6 +241,7 @@ public class Tester2 implements Runnable { Sqlite.Stmt stmt = db.prepare("SELECT ?1"); Exception e = null; affirm( null!=stmt.nativeHandle() ); + affirm( db == stmt.getDb() ); affirm( 1==stmt.bindParameterCount() ); affirm( "?1".equals(stmt.bindParameterName(1)) ); affirm( null==stmt.bindParameterName(2) ); @@ -294,21 +295,30 @@ public class Tester2 implements Runnable { final ValueHolder vh = new ValueHolder<>(0); final ScalarFunction f = new ScalarFunction(){ public void xFunc(SqlFunction.Arguments args){ + affirm( db == args.getDb() ); for( SqlFunction.Arguments.Arg arg : args ){ vh.value += arg.getInt(); } + args.resultInt(vh.value); } public void xDestroy(){ ++xDestroyCalled.value; } }; db.createFunction("myfunc", -1, f); - execSql(db, "select myfunc(1,2,3)"); + Sqlite.Stmt q = db.prepare("select myfunc(1,2,3)"); + affirm( q.step() ); affirm( 6 == vh.value ); - vh.value = 0; - execSql(db, "select myfunc(-1,-2,-3)"); - affirm( -6 == vh.value ); + affirm( 6 == q.columnInt(0) ); + q.finalizeStmt(); affirm( 0 == xDestroyCalled.value ); + vh.value = 0; + q = db.prepare("select myfunc(-1,-2,-3)"); + affirm( q.step() ); + affirm( -6 == vh.value ); + affirm( -6 == q.columnInt(0) ); + affirm( 0 == xDestroyCalled.value ); + q.finalizeStmt(); } affirm( 1 == xDestroyCalled.value ); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java index 479fc74d7f..a3905567d4 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java @@ -12,10 +12,6 @@ ** This file is part of the wrapper1 interface for sqlite3. */ package org.sqlite.jni.wrapper1; -import org.sqlite.jni.capi.CApi; -import org.sqlite.jni.annotation.*; -import org.sqlite.jni.capi.sqlite3_context; -import org.sqlite.jni.capi.sqlite3_value; /** A SqlFunction implementation for window functions. The T type diff --git a/manifest b/manifest index 5ee7dad393..661bf798a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rework\sthe\sJNI\swrapper1\svariants\sof\sstatus()\sand\sdb_status()\sto\sbe\smore\sJava-esque. -D 2023-11-04T13:37:42.589 +C Expose\scontext_db_handle()\sto\sthe\sJNI\swrapper1\sAPI\sand\sclean\sup\ssome\srelated\stests. +D 2023-11-04T16:01:13.004 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -293,14 +293,14 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java a8e88c3783d21cec51b0748568a96653 F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 9e2b954d210d572552b28aca523b272fae14bd41e318921b22f65b728d5bf978 F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ade23d329843f809cd0d0f4f1a2856da6e6b4d90 F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e -F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f +F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 -F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 0b01b9058ef6737c85b505c6aa2490fb1dc1d974fb39d88a93269fed09553f9f -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java ab6bee53895e5f7345b57d32ef30e9cc9c9c09979a31211f63e60dcdea9a7ab1 -F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java cbd087d3fcbfca384656fc2189a9b017e4afe70f0f17d8266d28c628ab97cada +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java e787f5f36d5832fe3c7a000a8609eb0629fb160b95f8f25566df13e72e6f5470 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3e813aa4a680948a1885a5df1537c9245b3b7362aaf6aa31f679640e81da020e +F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 96d7908da8bad591aff8f192cb83e038fd5861ef4601726eeda24905422718c9 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af -F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java 1a1afbafbd7406ff67e7d6405541c6347517c731de535a97d7a3df1d4db835b4 +F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70 F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0 @@ -2142,8 +2142,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 b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921 -R 9ee74b8e162e4e8a23028ccec92c6373 +P 40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8 +R f79739ffe6d4cd3ba58087c1ffb0d1f9 U stephan -Z ce3f2fb1a954c596b6cdbc560de71d23 +Z 05734d404abe66e6e03def34a1d0d490 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 18ae81abac..c78490991b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8 \ No newline at end of file +c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566 \ No newline at end of file From d4677f192ff63f5e670dc18afa9c78ab12e78c54 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 4 Nov 2023 21:44:00 +0000 Subject: [PATCH 05/55] Ensure that the YYYY-MM-DD input to date and time functions has been normalized prior to returning a result. [forum:/forumpost/6bb476897e|Forum post 6bb476897e]. FossilOrigin-Name: b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/date.c | 6 ++++++ test/date.test | 5 +++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 661bf798a5..eacc52b68c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\scontext_db_handle()\sto\sthe\sJNI\swrapper1\sAPI\sand\sclean\sup\ssome\srelated\stests. -D 2023-11-04T16:01:13.004 +C Ensure\sthat\sthe\sYYYY-MM-DD\sinput\sto\sdate\sand\stime\sfunctions\shas\sbeen\snormalized\nprior\sto\sreturning\sa\sresult.\n[forum:/forumpost/6bb476897e|Forum\spost\s6bb476897e]. +D 2023-11-04T21:44:00.659 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -670,7 +670,7 @@ F src/build.c 189e4517d67f09f0a3e0d8e1faa6e2ef0c2e95f6ac82e33c912cb7efa2a359cc F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b -F src/date.c eebc54a00e888d3c56147779e9f361b77d62fd69ff2008c5373946aa1ba1d574 +F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500 @@ -1016,7 +1016,7 @@ F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c47 F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270 F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8 -F test/date.test c0d17cdfd89395bc78087b131e3538d96f864b5029c335318011accc7c0d0934 +F test/date.test ff2341a1ef71b9a27979494d299222f9a293aa22cb9ff6e9c38d88a895317ebf F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1 F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5 F test/date4.test 8aeb3de5b5e9fda968baa9357e4c0fae573724b7904943410195a19e96e31b6a @@ -2142,8 +2142,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 40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8 -R f79739ffe6d4cd3ba58087c1ffb0d1f9 -U stephan -Z 05734d404abe66e6e03def34a1d0d490 +P c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566 +R 0a52dbd298d991529b412673e9dc7eb5 +U drh +Z 33b6056e932d878d8676b163d8b94db2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c78490991b..a2ff9c7a2a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566 \ No newline at end of file +b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5 \ No newline at end of file diff --git a/src/date.c b/src/date.c index f163085445..e493542db9 100644 --- a/src/date.c +++ b/src/date.c @@ -1043,6 +1043,12 @@ static int isDate( } computeJD(p); if( p->isError || !validJulianDay(p->iJD) ) return 1; + if( argc==1 && p->validYMD && p->D>28 ){ + /* Make sure a YYYY-MM-DD is normalized. + ** Example: 2023-02-31 -> 2023-03-03 */ + assert( p->validJD ); + p->validYMD = 0; + } return 0; } diff --git a/test/date.test b/test/date.test index fb76dac8ac..19cecc2db3 100644 --- a/test/date.test +++ b/test/date.test @@ -146,6 +146,8 @@ datetest 2.49 {datetime('2003-10-22 12:24','0000 second')} {2003-10-22 12:24:00} datetest 2.50 {datetime('2003-10-22 12:24','0001 second')} {2003-10-22 12:24:01} datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL +datetest 2.60 {datetime('2023-02-31')} {2023-03-03 00:00:00} + datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31 datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999 @@ -452,6 +454,9 @@ datetest 13.31 {date('2001-01-01','+1.5 years')} {2002-07-02} datetest 13.32 {date('2002-01-01','+1.5 years')} {2003-07-02} datetest 13.33 {date('2002-01-01','-1.5 years')} {2000-07-02} datetest 13.34 {date('2001-01-01','-1.5 years')} {1999-07-02} +datetest 13.35 {date('2023-02-28')} {2023-02-28} +datetest 13.36 {date('2023-02-29')} {2023-03-01} +datetest 13.37 {date('2023-04-31')} {2023-05-01} # Test for issues reported by BareFeet (list.sql at tandb.com.au) # on mailing list on 2008-06-12. From ffdb479e7c45c8870cae7be57173ed1d55234302 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 21:51:34 +0000 Subject: [PATCH 06/55] Reimplement auto-extensions in Java for use with the JNI wrapper1 API. FossilOrigin-Name: 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468 --- ext/jni/src/org/sqlite/jni/capi/CApi.java | 2 +- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 2 +- .../org/sqlite/jni/wrapper1/SqlFunction.java | 4 + .../src/org/sqlite/jni/wrapper1/Sqlite.java | 109 ++++++++++++++++-- .../src/org/sqlite/jni/wrapper1/Tester2.java | 77 +++++++++++++ manifest | 22 ++-- manifest.uuid | 2 +- 7 files changed, 194 insertions(+), 24 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index ef1ca17b22..79568e74ad 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -891,7 +891,7 @@ public final class CApi { } public static native boolean sqlite3_extended_result_codes( - @NotNull sqlite3 db, boolean onoff + @NotNull sqlite3 db, boolean on ); static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb); diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index fdadb3e29d..479b5f72bc 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1419,7 +1419,7 @@ public class Tester1 implements Runnable { val.value = 0; final AutoExtensionCallback ax2 = new AutoExtensionCallback(){ - @Override public synchronized int call(sqlite3 db){ + @Override public int call(sqlite3 db){ ++val.value; return 0; } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index 941800513d..b3317029c7 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -117,6 +117,10 @@ public interface SqlFunction { public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);} public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);} public void resultNull(){CApi.sqlite3_result_null(cx);} + /** + Analog to sqlite3_result_value(), using the Value object at the + given argument index. + */ public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));} public void resultSubtype(int subtype){CApi.sqlite3_result_subtype(cx, subtype);} public void resultZeroBlob(long n){ diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 4f14253a3e..298b6ae55e 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -13,7 +13,6 @@ */ package org.sqlite.jni.wrapper1; import java.nio.charset.StandardCharsets; -import static org.sqlite.jni.capi.CApi.*; import org.sqlite.jni.capi.CApi; import org.sqlite.jni.capi.sqlite3; import org.sqlite.jni.capi.sqlite3_stmt; @@ -129,7 +128,7 @@ public final class Sqlite implements AutoCloseable { */ public static Sqlite open(String filename, int flags, String vfsName){ final OutputPointer.sqlite3 out = new OutputPointer.sqlite3(); - final int rc = sqlite3_open_v2(filename, out, flags, vfsName); + final int rc = CApi.sqlite3_open_v2(filename, out, flags, vfsName); final sqlite3 n = out.take(); if( 0!=rc ){ if( null==n ) throw new SqliteException(rc); @@ -137,10 +136,11 @@ public final class Sqlite implements AutoCloseable { n.close(); throw ex; } - Sqlite rv = new Sqlite(n); + final Sqlite rv = new Sqlite(n); synchronized(nativeToWrapper){ nativeToWrapper.put(n, rv); } + runAutoExtensions(rv); return rv; } @@ -149,7 +149,7 @@ public final class Sqlite implements AutoCloseable { } public static Sqlite open(String filename){ - return open(filename, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, null); + return open(filename, OPEN_READWRITE|OPEN_CREATE, null); } public static String libVersion(){ @@ -308,7 +308,7 @@ public final class Sqlite implements AutoCloseable { if( 0!=rc ){ if( CApi.SQLITE_NOMEM==rc ){ throw new OutOfMemoryError(); - }else if( null==db || 0==sqlite3_errcode(db)){ + }else if( null==db || 0==CApi.sqlite3_errcode(db)){ throw new SqliteException(rc); }else{ throw new SqliteException(db); @@ -343,7 +343,7 @@ public final class Sqlite implements AutoCloseable { */ public Stmt prepare(String sql, int prepFlags){ final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt(); - final int rc = sqlite3_prepare_v3(thisDb(), sql, prepFlags, out); + final int rc = CApi.sqlite3_prepare_v3(thisDb(), sql, prepFlags, out); checkRc(rc); final sqlite3_stmt q = out.take(); if( null==q ){ @@ -724,7 +724,7 @@ public final class Sqlite implements AutoCloseable { synchronized(nativeToWrapper){ nativeToWrapper.remove(this.stmt); } - sqlite3_finalize(stmt); + CApi.sqlite3_finalize(stmt); stmt = null; _db = null; resultColCount = 0; @@ -745,8 +745,8 @@ public final class Sqlite implements AutoCloseable { private int checkRc(int rc){ switch(rc){ case 0: - case SQLITE_ROW: - case SQLITE_DONE: return rc; + case CApi.SQLITE_ROW: + case CApi.SQLITE_DONE: return rc; default: if( null==stmt ) throw new SqliteException(rc); else throw new SqliteException(this); @@ -759,7 +759,7 @@ public final class Sqlite implements AutoCloseable { result. */ public boolean step(){ - switch(checkRc(sqlite3_step(thisStmt()))){ + switch(checkRc(CApi.sqlite3_step(thisStmt()))){ case CApi.SQLITE_ROW: return true; case CApi.SQLITE_DONE: return false; default: @@ -930,4 +930,93 @@ public final class Sqlite implements AutoCloseable { } } /* Stmt class */ + /** + Interface for auto-extensions, as per the + sqlite3_auto_extension() API. + + Design note: the chicken/egg timing of auto-extension execution + requires that this feature be entirely re-implemented in Java + because the C-level API has no access to the Sqlite type so + cannot pass on an object of that type while the database is being + opened. One side effect of this reimplementation is that this + class's list of auto-extensions is 100% independent of the + C-level list so, e.g., clearAutoExtensions() will have no effect + on auto-extensions added via the C-level API and databases opened + from that level of API will not be passed to this level's + AutoExtension instances. + */ + public interface AutoExtension { + public void call(Sqlite db); + } + + private static final java.util.Set autoExtensions = + new java.util.LinkedHashSet<>(); + + /** + Passes db to all auto-extensions. If any one of them throws, + db.close() is called before the exception is propagated. + */ + private static void runAutoExtensions(Sqlite db){ + AutoExtension list[]; + synchronized(autoExtensions){ + /* Avoid that modifications to the AutoExtension list from within + auto-extensions affect this execution of this list. */ + list = autoExtensions.toArray(new AutoExtension[0]); + } + try { + for( AutoExtension ax : list ) ax.call(db); + }catch(Exception e){ + db.close(); + throw e; + } + } + + /** + Analog to sqlite3_auto_extension(), adds the given object to the + list of auto-extensions if it is not already in that list. The + given object will be run as part of Sqlite.open(), and passed the + being-opened database. If the extension throws then open() will + fail. + + This API does not guaranty whether or not manipulations made to + the auto-extension list from within auto-extension callbacks will + affect the current traversal of the auto-extension list. Whether + or not they do is unspecified and subject to change between + versions. e.g. if an AutoExtension calls addAutoExtension(), + whether or not the new extension will be run on the being-opened + database is undefined. + + Note that calling Sqlite.open() from an auto-extension will + necessarily result in recursion loop and (eventually) a stack + overflow. + */ + public static void addAutoExtension( AutoExtension e ){ + if( null==e ){ + throw new IllegalArgumentException("AutoExtension may not be null."); + } + synchronized(autoExtensions){ + autoExtensions.add(e); + } + } + + /** + Removes the given object from the auto-extension list if it is in + that list, otherwise this has no side-effects beyond briefly + locking that list. + */ + public static void removeAutoExtension( AutoExtension e ){ + synchronized(autoExtensions){ + autoExtensions.remove(e); + } + } + + /** + Removes all auto-extensions which were added via addAutoExtension(). + */ + public static void clearAutoExtensions(){ + synchronized(autoExtensions){ + autoExtensions.clear(); + } + } + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 5f991da4d3..4402ea6b3a 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -526,6 +526,83 @@ public class Tester2 implements Runnable { db.close(); } + @SingleThreadOnly /* because multiple threads legitimately make these + results unpredictable */ + private synchronized void testAutoExtension(){ + final ValueHolder val = new ValueHolder<>(0); + final ValueHolder toss = new ValueHolder<>(null); + final Sqlite.AutoExtension ax = new Sqlite.AutoExtension(){ + @Override public void call(Sqlite db){ + ++val.value; + if( null!=toss.value ){ + throw new RuntimeException(toss.value); + } + } + }; + Sqlite.addAutoExtension(ax); + openDb().close(); + affirm( 1==val.value ); + openDb().close(); + affirm( 2==val.value ); + Sqlite.clearAutoExtensions(); + openDb().close(); + affirm( 2==val.value ); + + Sqlite.addAutoExtension( ax ); + Sqlite.addAutoExtension( ax ); // Must not add a second entry + Sqlite.addAutoExtension( ax ); // or a third one + openDb().close(); + affirm( 3==val.value ); + + Sqlite db = openDb(); + affirm( 4==val.value ); + execSql(db, "ATTACH ':memory:' as foo"); + affirm( 4==val.value, "ATTACH uses the same connection, not sub-connections." ); + db.close(); + db = null; + + Sqlite.removeAutoExtension(ax); + openDb().close(); + affirm( 4==val.value ); + Sqlite.addAutoExtension(ax); + Exception err = null; + toss.value = "Throwing from auto_extension."; + try{ + openDb(); + }catch(Exception e){ + err = e; + } + affirm( err!=null ); + affirm( err.getMessage().indexOf(toss.value)>=0 ); + toss.value = null; + + val.value = 0; + final Sqlite.AutoExtension ax2 = new Sqlite.AutoExtension(){ + @Override public void call(Sqlite db){ + ++val.value; + } + }; + Sqlite.addAutoExtension(ax2); + openDb().close(); + affirm( 2 == val.value ); + Sqlite.removeAutoExtension(ax); + openDb().close(); + affirm( 3 == val.value ); + Sqlite.addAutoExtension(ax); + openDb().close(); + affirm( 5 == val.value ); + Sqlite.removeAutoExtension(ax2); + openDb().close(); + affirm( 6 == val.value ); + Sqlite.addAutoExtension(ax2); + openDb().close(); + affirm( 8 == val.value ); + + Sqlite.clearAutoExtensions(); + openDb().close(); + affirm( 8 == val.value ); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index eacc52b68c..23488e42ad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sthe\sYYYY-MM-DD\sinput\sto\sdate\sand\stime\sfunctions\shas\sbeen\snormalized\nprior\sto\sreturning\sa\sresult.\n[forum:/forumpost/6bb476897e|Forum\spost\s6bb476897e]. -D 2023-11-04T21:44:00.659 +C Reimplement\sauto-extensions\sin\sJava\sfor\suse\swith\sthe\sJNI\swrapper1\sAPI. +D 2023-11-04T21:51:34.589 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java d21e6c1c4557ae18bbc2eefb0882efdb36fdaecdc58823c142def994327a365b +F ext/jni/src/org/sqlite/jni/capi/CApi.java 4043d709626079cce6d524ef49122b934c043022bd88bc1e72eb697ac8df86e7 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 41e2b910a11dfdd4cc39ab608492d7c12f3791e85ac7f9d75d5445f7645a5e57 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 96c27ae10ec44ce5f6a150e8bc6525d86ab2d9118da18649943a0bf4d8d206ce F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -295,10 +295,10 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ad F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 -F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java e787f5f36d5832fe3c7a000a8609eb0629fb160b95f8f25566df13e72e6f5470 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3e813aa4a680948a1885a5df1537c9245b3b7362aaf6aa31f679640e81da020e +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3da22cb18d8544fff1c7184aeaa2516c20d63e8a31db848eb7470ce285b284dc F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 96d7908da8bad591aff8f192cb83e038fd5861ef4601726eeda24905422718c9 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 03638a1774a95bcc7b5de440a5f1398720460e30fc480032a2e8be24e997d30c F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566 -R 0a52dbd298d991529b412673e9dc7eb5 -U drh -Z 33b6056e932d878d8676b163d8b94db2 +P b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5 +R 99817a8518af3f567a07823f0172a1fb +U stephan +Z 276f4a4bca9307a54b6144f3c8e4f323 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a2ff9c7a2a..89c3bcfb2b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5 \ No newline at end of file +14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468 \ No newline at end of file From dc8a684c11113b9e2ce8fa5c0372f57fcd8c7869 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 22:47:40 +0000 Subject: [PATCH 07/55] Wrap the sqlite3_backup API in the JNI wrapper1 API. FossilOrigin-Name: 3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2 --- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 119 ++++++++++++++++-- .../src/org/sqlite/jni/wrapper1/Tester2.java | 35 ++++++ manifest | 14 +-- manifest.uuid | 2 +- 4 files changed, 154 insertions(+), 16 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 298b6ae55e..85b5460f34 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets; import org.sqlite.jni.capi.CApi; import org.sqlite.jni.capi.sqlite3; import org.sqlite.jni.capi.sqlite3_stmt; +import org.sqlite.jni.capi.sqlite3_backup; import org.sqlite.jni.capi.OutputPointer; /** @@ -767,14 +768,6 @@ public final class Sqlite implements AutoCloseable { "This \"cannot happen\": all possible result codes were checked already." ); } - /* - Potential signature change TODO: - - boolean step() - - Returning true for SQLITE_ROW and false for anything else. - Those semantics have proven useful in the WASM/JS bindings. - */ } /** @@ -1019,4 +1012,114 @@ public final class Sqlite implements AutoCloseable { } } + /** + Encapsulates state related to the sqlite3 backup API. Use + Sqlite.initBackup() to create new instances. + */ + public static final class Backup implements AutoCloseable { + private sqlite3_backup b = null; + private Sqlite dbTo = null; + private Sqlite dbFrom = null; + + + public static final int DONE = CApi.SQLITE_DONE; + public static final int BUSY = CApi.SQLITE_BUSY; + public static final int LOCKED = CApi.SQLITE_LOCKED; + + Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){ + this.dbTo = dbDest; + this.dbFrom = dbSrc; + b = CApi.sqlite3_backup_init(dbDest.nativeHandle(), schemaDest, + dbSrc.nativeHandle(), schemaSrc); + if(null==b) toss(); + } + + private void toss(){ + int rc = CApi.sqlite3_errcode(dbTo.nativeHandle()); + if(0!=rc) throw new SqliteException(dbTo); + rc = CApi.sqlite3_errcode(dbFrom.nativeHandle()); + if(0!=rc) throw new SqliteException(dbFrom); + throw new SqliteException(CApi.SQLITE_ERROR); + } + + private sqlite3_backup getNative(){ + if( null==b ) throw new IllegalStateException("This Backup is already closed."); + return b; + } + /** + If this backup is still active, this completes the backup and + frees its native resources, otherwise it this is a no-op. + */ + public void finish(){ + if( null!=b ){ + CApi.sqlite3_backup_finish(b); + b = null; + dbTo = null; + dbFrom = null; + } + } + + /** Equivalent to finish(). */ + @Override public void close(){ + this.finish(); + } + + /** + Analog to sqlite3_backup_step(). Returns 0 if stepping succeeds + or, DONE if the end is reached, BUSY if one of the databases is + busy, LOCKED if one of the databases is locked, and throws for + any other result code or if this object has been closed. Note + that BUSY and LOCKED are not necessarily permanent errors, so + do not trigger an exception. + */ + public int step(int pageCount){ + final int rc = CApi.sqlite3_backup_step(getNative(), pageCount); + switch(rc){ + case 0: + case DONE: + case BUSY: + case LOCKED: + return rc; + default: + toss(); + return CApi.SQLITE_ERROR/*not reached*/; + } + } + + /** + Analog to sqlite3_backup_pagecount(). + */ + public int pageCount(){ + return CApi.sqlite3_backup_pagecount(getNative()); + } + + /** + Analog to sqlite3_backup_remaining(). + */ + public int remaining(){ + return CApi.sqlite3_backup_remaining(getNative()); + } + } + + /** + Analog to sqlite3_backup_init(). If schemaSrc is null, "main" is + assumed. Throws if either this db or dbSrc (the source db) are + not opened, if either of schemaDest or schemaSrc are null, or if + the underlying call to sqlite3_backup_init() fails. + + The returned object must eventually be cleaned up by either + arranging for it to be auto-closed (e.g. using + try-with-resources) or by calling its finish() method. + */ + public Backup initBackup(String schemaDest, Sqlite dbSrc, String schemaSrc){ + thisDb(); + dbSrc.thisDb(); + if( null==schemaSrc || null==schemaDest ){ + throw new IllegalArgumentException( + "Neither the source nor destination schema name may be null." + ); + } + return new Backup(this, schemaDest, dbSrc, schemaSrc); + } + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 4402ea6b3a..d305d6b719 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -603,6 +603,41 @@ public class Tester2 implements Runnable { affirm( 8 == val.value ); } + private void testBackup(){ + final Sqlite dbDest = openDb(); + + try (Sqlite dbSrc = openDb()) { + execSql(dbSrc, new String[]{ + "pragma page_size=512; VACUUM;", + "create table t(a);", + "insert into t(a) values(1),(2),(3);" + }); + Exception e = null; + try { + dbSrc.initBackup("main",dbSrc,"main"); + }catch(Exception x){ + e = x; + } + affirm( e instanceof SqliteException ); + e = null; + try (Sqlite.Backup b = dbDest.initBackup("main",dbSrc,"main")) { + affirm( null!=b ); + int rc; + while( Sqlite.Backup.DONE!=(rc = b.step(1)) ){ + affirm( 0==rc ); + } + affirm( b.pageCount() > 0 ); + b.finish(); + } + } + + try (Sqlite.Stmt q = dbDest.prepare("SELECT sum(a) from t")) { + q.step(); + affirm( q.columnInt(0) == 6 ); + } + dbDest.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 23488e42ad..234186ce10 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reimplement\sauto-extensions\sin\sJava\sfor\suse\swith\sthe\sJNI\swrapper1\sAPI. -D 2023-11-04T21:51:34.589 +C Wrap\sthe\ssqlite3_backup\sAPI\sin\sthe\sJNI\swrapper1\sAPI. +D 2023-11-04T22:47:40.514 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3da22cb18d8544fff1c7184aeaa2516c20d63e8a31db848eb7470ce285b284dc +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 8dd4cce0f0a42542af768a73c3c9e7bebd1c77207a35ba93de86c97d4c572847 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 03638a1774a95bcc7b5de440a5f1398720460e30fc480032a2e8be24e997d30c +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 3c2eda2efe45a051e371ba98abee34f51ceec3bb7d28dfde866646b650fcb426 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5 -R 99817a8518af3f567a07823f0172a1fb +P 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468 +R 631890601bc1abeba3be592d27b2aeb0 U stephan -Z 276f4a4bca9307a54b6144f3c8e4f323 +Z 39a1f06f24f0b71c35deac1228d090c6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 89c3bcfb2b..5235b01fd9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468 \ No newline at end of file +3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2 \ No newline at end of file From 15d38c0ddeb98168e0bca78a6a15d99f7092e225 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 4 Nov 2023 23:37:11 +0000 Subject: [PATCH 08/55] Bind collation and collation-needed to JNI wrapper1 and correct the callback return type for collation-needed callbacks in the lower-level JNI binding. FossilOrigin-Name: 0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe --- ext/jni/src/c/sqlite3-jni.c | 2 +- .../jni/capi/CollationNeededCallback.java | 7 +- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 4 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 97 +++++++++++++++++++ .../src/org/sqlite/jni/wrapper1/Tester2.java | 61 ++++++++++++ manifest | 20 ++-- manifest.uuid | 2 +- 7 files changed, 176 insertions(+), 17 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index e6b0750cbd..bf4e73b7c3 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -2817,7 +2817,7 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)( }else{ jclass const klazz = (*env)->GetObjectClass(env, jHook); jmethodID const xCallback = (*env)->GetMethodID( - env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I" + env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)V" ); S3JniUnrefLocal(klazz); S3JniIfThrew { diff --git a/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java b/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java index fe61fe5065..ffd7fa94ab 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java @@ -21,8 +21,9 @@ public interface CollationNeededCallback extends CallbackProxy { Has the same semantics as the C-level sqlite3_create_collation() callback. -

If it throws, the exception message is passed on to the db and - the exception is suppressed. +

Because the C API has no mechanism for reporting errors + from this callbacks, any exceptions thrown by this callback + are suppressed. */ - int call(sqlite3 db, int eTextRep, String collationName); + void call(sqlite3 db, int eTextRep, String collationName); } diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 479b5f72bc..b97d568de8 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -593,9 +593,9 @@ public class Tester1 implements Runnable { }; final CollationNeededCallback collLoader = new CollationNeededCallback(){ @Override - public int call(sqlite3 dbArg, int eTextRep, String collationName){ + public void call(sqlite3 dbArg, int eTextRep, String collationName){ affirm(dbArg == db/* as opposed to a temporary object*/); - return sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation); + sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation); } }; int rc = sqlite3_collation_needed(db, collLoader); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 85b5460f34..80122cd350 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -100,6 +100,13 @@ public final class Sqlite implements AutoCloseable { public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS; public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER; + public static final int UTF8 = CApi.SQLITE_UTF8; + public static final int UTF16 = CApi.SQLITE_UTF16; + public static final int UTF16LE = CApi.SQLITE_UTF16LE; + public static final int UTF16BE = CApi.SQLITE_UTF16BE; + /* We elide the UTF16_ALIGNED from this interface because it + is irrelevant for the Java interface. */ + //! Used only by the open() factory functions. private Sqlite(sqlite3 db){ this.db = db; @@ -1122,4 +1129,94 @@ public final class Sqlite implements AutoCloseable { return new Backup(this, schemaDest, dbSrc, schemaSrc); } + + /** + Callback type for use with createCollation(). + */ + public interface Collation { + /** + Called by the SQLite core to compare inputs. Implementations + must compare its two arguments using memcmp(3) semantics. + + Warning: the SQLite core has no mechanism for reporting errors + from custom collations and its workflow does not accommodate + propagation of exceptions from callbacks. Any exceptions thrown + from collations will be silently supressed and sorting results + will be unpredictable. + */ + int call(byte[] lhs, byte[] rhs); + } + + /** + Analog to sqlite3_create_collation(). + + Throws if name is null or empty, c is null, or the encoding flag + is invalid. The encoding must be one of the UTF8, UTF16, UTF16LE, + or UTF16BE constants. + */ + public void createCollation(String name, int encoding, Collation c){ + thisDb(); + if( null==name || 0==name.length()){ + throw new IllegalArgumentException("Collation name may not be null or empty."); + } + if( null==c ){ + throw new IllegalArgumentException("Collation may not be null."); + } + switch(encoding){ + case UTF8: + case UTF16: + case UTF16LE: + case UTF16BE: + break; + default: + throw new IllegalArgumentException("Invalid Collation encoding."); + } + checkRc( + CApi.sqlite3_create_collation( + thisDb(), name, encoding, new org.sqlite.jni.capi.CollationCallback(){ + @Override public int call(byte[] lhs, byte[] rhs){ + try{return c.call(lhs, rhs);} + catch(Exception e){return 0;} + } + @Override public void xDestroy(){} + } + ) + ); + } + + /** + Callback for use with onCollationNeeded(). + */ + public interface CollationNeeded { + /** + Must behave as documented for the callback for + sqlite3_collation_needed(). + + Warning: the C API has no mechanism for reporting or + propagating errors from this callback, so any exceptions it + throws are suppressed. + */ + void call(Sqlite db, int encoding, String collationName); + } + + /** + Sets up the given object to be called by the SQLite core when it + encounters a collation name which it does not know. Pass a null + object to disconnect the object from the core. This replaces any + existing collation-needed loader, or is a no-op if the given + object is already registered. Throws if registering the loader + fails. + */ + public void onCollationNeeded( CollationNeeded cn ){ + org.sqlite.jni.capi.CollationNeededCallback cnc = null; + if( null!=cn ){ + cnc = new org.sqlite.jni.capi.CollationNeededCallback(){ + @Override public void call(sqlite3 db, int encoding, String collationName){ + final Sqlite xdb = Sqlite.fromNative(db); + if(null!=xdb) cn.call(xdb, encoding, collationName); + } + }; + } + checkRc( CApi.sqlite3_collation_needed(thisDb(), cnc) ); + } } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index d305d6b719..6ca0be5d17 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -638,6 +638,67 @@ public class Tester2 implements Runnable { dbDest.close(); } + private void testCollation(){ + final Sqlite db = openDb(); + execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')"); + final Sqlite.Collation myCollation = new Sqlite.Collation() { + private String myState = + "this is local state. There is much like it, but this is mine."; + @Override + // Reverse-sorts its inputs... + public int call(byte[] lhs, byte[] rhs){ + int len = lhs.length > rhs.length ? rhs.length : lhs.length; + int c = 0, i = 0; + for(i = 0; i < len; ++i){ + c = lhs[i] - rhs[i]; + if(0 != c) break; + } + if(0==c){ + if(i < lhs.length) c = 1; + else if(i < rhs.length) c = -1; + } + return -c; + } + }; + final Sqlite.CollationNeeded collLoader = new Sqlite.CollationNeeded(){ + @Override + public void call(Sqlite dbArg, int eTextRep, String collationName){ + affirm(dbArg == db); + db.createCollation("reversi", eTextRep, myCollation); + } + }; + db.onCollationNeeded(collLoader); + Sqlite.Stmt stmt = db.prepare("SELECT a FROM t ORDER BY a COLLATE reversi"); + int counter = 0; + while( stmt.step() ){ + final String val = stmt.columnText16(0); + ++counter; + switch(counter){ + case 1: affirm("c".equals(val)); break; + case 2: affirm("b".equals(val)); break; + case 3: affirm("a".equals(val)); break; + } + } + affirm(3 == counter); + stmt.finalizeStmt(); + stmt = db.prepare("SELECT a FROM t ORDER BY a"); + counter = 0; + while( stmt.step() ){ + final String val = stmt.columnText16(0); + ++counter; + //outln("Non-REVERSI'd row#"+counter+": "+val); + switch(counter){ + case 3: affirm("c".equals(val)); break; + case 2: affirm("b".equals(val)); break; + case 1: affirm("a".equals(val)); break; + } + } + affirm(3 == counter); + stmt.finalizeStmt(); + db.onCollationNeeded(null); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 234186ce10..2453b24fde 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Wrap\sthe\ssqlite3_backup\sAPI\sin\sthe\sJNI\swrapper1\sAPI. -D 2023-11-04T22:47:40.514 +C Bind\scollation\sand\scollation-needed\sto\sJNI\swrapper1\sand\scorrect\sthe\scallback\sreturn\stype\sfor\scollation-needed\scallbacks\sin\sthe\slower-level\sJNI\sbinding. +D 2023-11-04T23:37:11.738 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 53493819418048bfdc8e6f505954c7e692d4666b64c3ae732ea8319c91aac747 +F ext/jni/src/c/sqlite3-jni.c 931a7320f5b5745034b4fd61027ea7cc29559856e6da613e4fdcf01ef102e710 F ext/jni/src/c/sqlite3-jni.h 1c45fd4689cec42f3d84d2fee41bb494016a12fcb5fd80291095590666a14015 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -254,7 +254,7 @@ F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04 F ext/jni/src/org/sqlite/jni/capi/CApi.java 4043d709626079cce6d524ef49122b934c043022bd88bc1e72eb697ac8df86e7 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a -F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95 +F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 29c002f3c638cc80f7db1594564a262d1beb32637824c3dca2d60a224d1f71d7 F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4 F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 96c27ae10ec44ce5f6a150e8bc6525d86ab2d9118da18649943a0bf4d8d206ce +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 8823d962f283aa7af5878d1a87b759ca03e1c9519ae692077f785eab81c86f3f F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 8dd4cce0f0a42542af768a73c3c9e7bebd1c77207a35ba93de86c97d4c572847 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 6a861cfc8b3284c07cf2fa88916deab27f98e9e4234fae1bed1917c933c64083 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 3c2eda2efe45a051e371ba98abee34f51ceec3bb7d28dfde866646b650fcb426 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java a4e4b0b8ee0d56a383fd57b24244c6f93f8a0fe2e2ba5faacc0a3331f8d3fc84 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468 -R 631890601bc1abeba3be592d27b2aeb0 +P 3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2 +R ef3119e103f71f255ed5e129f7bdb70b U stephan -Z 39a1f06f24f0b71c35deac1228d090c6 +Z 99a7727c5c06597d0eb0c0df96988bd8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5235b01fd9..48f7c632aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2 \ No newline at end of file +0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe \ No newline at end of file From b02ca781ad2e8e375ccce4c1259a9b466eac0f68 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 00:02:47 +0000 Subject: [PATCH 09/55] Add busy-handler support to JNI wrapper1. FossilOrigin-Name: dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20 --- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 83 +++++++++---------- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 68 +++++++++++---- .../src/org/sqlite/jni/wrapper1/Tester2.java | 40 ++++++++- manifest | 16 ++-- manifest.uuid | 2 +- 5 files changed, 140 insertions(+), 69 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index b97d568de8..48ab031466 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1031,49 +1031,48 @@ public class Tester1 implements Runnable { @SingleThreadOnly /* because threads inherently break this test */ private static void testBusy(){ final String dbName = "_busy-handler.db"; - final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3(); - final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); - - int rc = sqlite3_open(dbName, outDb); - ++metrics.dbOpen; - affirm( 0 == rc ); - final sqlite3 db1 = outDb.get(); - execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)"); - rc = sqlite3_open(dbName, outDb); - ++metrics.dbOpen; - affirm( 0 == rc ); - affirm( outDb.get() != db1 ); - final sqlite3 db2 = outDb.get(); - - affirm( "main".equals( sqlite3_db_name(db1, 0) ) ); - rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo"); - affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) ); - affirm( "foo".equals( sqlite3_db_name(db1, 0) ) ); - affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) ); - - final ValueHolder xBusyCalled = new ValueHolder<>(0); - BusyHandlerCallback handler = new BusyHandlerCallback(){ - @Override public int call(int n){ - //outln("busy handler #"+n); - return n > 2 ? 0 : ++xBusyCalled.value; - } - }; - rc = sqlite3_busy_handler(db2, handler); - affirm(0 == rc); - - // Force a locked condition... - execSql(db1, "BEGIN EXCLUSIVE"); - rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt); - affirm( SQLITE_BUSY == rc); - affirm( null == outStmt.get() ); - affirm( 3 == xBusyCalled.value ); - sqlite3_close_v2(db1); - sqlite3_close_v2(db2); try{ - final java.io.File f = new java.io.File(dbName); - f.delete(); - }catch(Exception e){ - /* ignore */ + final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3(); + final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); + + int rc = sqlite3_open(dbName, outDb); + ++metrics.dbOpen; + affirm( 0 == rc ); + final sqlite3 db1 = outDb.get(); + execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)"); + rc = sqlite3_open(dbName, outDb); + ++metrics.dbOpen; + affirm( 0 == rc ); + affirm( outDb.get() != db1 ); + final sqlite3 db2 = outDb.get(); + + affirm( "main".equals( sqlite3_db_name(db1, 0) ) ); + rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo"); + affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) ); + affirm( "foo".equals( sqlite3_db_name(db1, 0) ) ); + affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) ); + + final ValueHolder xBusyCalled = new ValueHolder<>(0); + BusyHandlerCallback handler = new BusyHandlerCallback(){ + @Override public int call(int n){ + //outln("busy handler #"+n); + return n > 2 ? 0 : ++xBusyCalled.value; + } + }; + rc = sqlite3_busy_handler(db2, handler); + affirm(0 == rc); + + // Force a locked condition... + execSql(db1, "BEGIN EXCLUSIVE"); + rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt); + affirm( SQLITE_BUSY == rc); + affirm( null == outStmt.get() ); + affirm( 3 == xBusyCalled.value ); + sqlite3_close_v2(db1); + sqlite3_close_v2(db2); + }finally{ + try{(new java.io.File(dbName)).delete();} + catch(Exception e){/* ignore */} } } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 80122cd350..ffbc695242 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -32,6 +32,7 @@ public final class Sqlite implements AutoCloseable { public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE; public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE; public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE; + public static final int TXN_NONE = CApi.SQLITE_TXN_NONE; public static final int TXN_READ = CApi.SQLITE_TXN_READ; public static final int TXN_WRITE = CApi.SQLITE_TXN_WRITE; @@ -107,6 +108,10 @@ public final class Sqlite implements AutoCloseable { /* We elide the UTF16_ALIGNED from this interface because it is irrelevant for the Java interface. */ + public static final int DONE = CApi.SQLITE_DONE; + public static final int BUSY = CApi.SQLITE_BUSY; + public static final int LOCKED = CApi.SQLITE_LOCKED; + //! Used only by the open() factory functions. private Sqlite(sqlite3 db){ this.db = db; @@ -430,10 +435,6 @@ public final class Sqlite implements AutoCloseable { return CApi.sqlite3_get_autocommit(thisDb()); } - public void setBusyTimeout(int ms){ - checkRc(CApi.sqlite3_busy_timeout(thisDb(), ms)); - } - /** Analog to sqlite3_txn_state(). Returns one of TXN_NONE, TXN_READ, or TXN_WRITE to denote this database's current transaction state @@ -1028,11 +1029,6 @@ public final class Sqlite implements AutoCloseable { private Sqlite dbTo = null; private Sqlite dbFrom = null; - - public static final int DONE = CApi.SQLITE_DONE; - public static final int BUSY = CApi.SQLITE_BUSY; - public static final int LOCKED = CApi.SQLITE_LOCKED; - Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){ this.dbTo = dbDest; this.dbFrom = dbSrc; @@ -1073,19 +1069,19 @@ public final class Sqlite implements AutoCloseable { /** Analog to sqlite3_backup_step(). Returns 0 if stepping succeeds - or, DONE if the end is reached, BUSY if one of the databases is - busy, LOCKED if one of the databases is locked, and throws for - any other result code or if this object has been closed. Note - that BUSY and LOCKED are not necessarily permanent errors, so - do not trigger an exception. + or, Sqlite.DONE if the end is reached, Sqlite.BUSY if one of + the databases is busy, Sqlite.LOCKED if one of the databases is + locked, and throws for any other result code or if this object + has been closed. Note that BUSY and LOCKED are not necessarily + permanent errors, so do not trigger an exception. */ public int step(int pageCount){ final int rc = CApi.sqlite3_backup_step(getNative(), pageCount); switch(rc){ case 0: - case DONE: - case BUSY: - case LOCKED: + case Sqlite.DONE: + case Sqlite.BUSY: + case Sqlite.LOCKED: return rc; default: toss(); @@ -1219,4 +1215,42 @@ public final class Sqlite implements AutoCloseable { } checkRc( CApi.sqlite3_collation_needed(thisDb(), cnc) ); } + + /** + Callback for use with busyHandler(). + */ + public interface BusyHandler { + /** + Must function as documented for the C-level + sqlite3_busy_handler() callback argument, minus the (void*) + argument the C-level function requires. + + If this function throws, it is translated to a database-level + error. + */ + int call(int n); + } + + /** + Analog to sqlite3_busy_timeout(). + */ + public void setBusyTimeout(int ms){ + checkRc(CApi.sqlite3_busy_timeout(thisDb(), ms)); + } + + /** + Analog to sqlite3_busy_handler(). If b is null then any + current handler is cleared. + */ + void setBusyHandler( BusyHandler b ){ + org.sqlite.jni.capi.BusyHandlerCallback bhc = null; + if( null!=b ){ + bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){ + @Override public int call(int n){ + return b.call(n); + } + }; + } + checkRc( CApi.sqlite3_busy_handler(thisDb(), bhc) ); + } } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 6ca0be5d17..3a00c0953f 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -623,7 +623,7 @@ public class Tester2 implements Runnable { try (Sqlite.Backup b = dbDest.initBackup("main",dbSrc,"main")) { affirm( null!=b ); int rc; - while( Sqlite.Backup.DONE!=(rc = b.step(1)) ){ + while( Sqlite.DONE!=(rc = b.step(1)) ){ affirm( 0==rc ); } affirm( b.pageCount() > 0 ); @@ -699,6 +699,44 @@ public class Tester2 implements Runnable { db.close(); } + @SingleThreadOnly /* because threads inherently break this test */ + private void testBusy(){ + final String dbName = "_busy-handler.db"; + try{ + Sqlite db1 = openDb(dbName); + ++metrics.dbOpen; + execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)"); + Sqlite db2 = openDb(dbName); + ++metrics.dbOpen; + + final ValueHolder xBusyCalled = new ValueHolder<>(0); + Sqlite.BusyHandler handler = new Sqlite.BusyHandler(){ + @Override public int call(int n){ + return n > 2 ? 0 : ++xBusyCalled.value; + } + }; + db2.setBusyHandler(handler); + + // Force a locked condition... + execSql(db1, "BEGIN EXCLUSIVE"); + int rc = 0; + SqliteException ex = null; + try{ + db2.prepare("SELECT * from t"); + }catch(SqliteException x){ + ex = x; + } + affirm( null!=ex ); + affirm( Sqlite.BUSY == ex.errcode() ); + affirm( 3 == xBusyCalled.value ); + db1.close(); + db2.close(); + }finally{ + try{(new java.io.File(dbName)).delete();} + catch(Exception e){/* ignore */} + } + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 2453b24fde..0cdcd1cfcd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\scollation\sand\scollation-needed\sto\sJNI\swrapper1\sand\scorrect\sthe\scallback\sreturn\stype\sfor\scollation-needed\scallbacks\sin\sthe\slower-level\sJNI\sbinding. -D 2023-11-04T23:37:11.738 +C Add\sbusy-handler\ssupport\sto\sJNI\swrapper1. +D 2023-11-05T00:02:47.384 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 8823d962f283aa7af5878d1a87b759ca03e1c9519ae692077f785eab81c86f3f +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 4bb5e62907a422a80a0fccbcb83085e9163c2c245451312a62c7550a45d16683 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 6a861cfc8b3284c07cf2fa88916deab27f98e9e4234fae1bed1917c933c64083 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java c930ca964f605ba8f175d3b0c85099d7f93069b59bf825929c9eef9e68ac96c5 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java a4e4b0b8ee0d56a383fd57b24244c6f93f8a0fe2e2ba5faacc0a3331f8d3fc84 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 6f5fae3c3827ca42ef124c319b24907483aadda69b7453173f7807e0a94f33dd F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2 -R ef3119e103f71f255ed5e129f7bdb70b +P 0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe +R 2dabe33af17a981e8c8323ecd84b4487 U stephan -Z 99a7727c5c06597d0eb0c0df96988bd8 +Z c2d53a448e9f555de7ff26068d4eba40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 48f7c632aa..97de8be89b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe \ No newline at end of file +dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20 \ No newline at end of file From 2c930e3b86028a108cab9008b75665d32cdd11c5 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 00:48:43 +0000 Subject: [PATCH 10/55] Add commit/rollback hook support to JNI wrapper1. FossilOrigin-Name: ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8 --- ext/jni/src/c/sqlite3-jni.c | 5 +- .../sqlite/jni/capi/CommitHookCallback.java | 3 +- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 3 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 101 ++++++++++++++++++ .../src/org/sqlite/jni/wrapper1/Tester2.java | 81 ++++++++++++++ manifest | 20 ++-- manifest.uuid | 2 +- 7 files changed, 201 insertions(+), 14 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index bf4e73b7c3..0d60e49d13 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -2942,7 +2942,10 @@ static int s3jni_commit_rollback_hook_impl(int isCommit, S3JniDb * const ps){ ? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback) : (int)((*env)->CallVoidMethod(env, hook.jObj, hook.midCallback), 0); S3JniIfThrew{ - rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR, "hook callback threw"); + rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR, + isCommit + ? "Commit hook callback threw" + : "Rollback hook callback threw"); } S3JniHook_localundup(hook); } diff --git a/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java index 24373bdf2b..e1e55c78d2 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java @@ -19,7 +19,8 @@ package org.sqlite.jni.capi; public interface CommitHookCallback extends CallbackProxy { /** Works as documented for the C-level sqlite3_commit_hook() - callback. Must not throw. + callback. If it throws, the exception is translated into + a db-level error. */ int call(); } diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 48ab031466..4a8ceb1812 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1096,6 +1096,7 @@ public class Tester1 implements Runnable { private void testCommitHook(){ final sqlite3 db = createNewDb(); + sqlite3_extended_result_codes(db, true); final ValueHolder counter = new ValueHolder<>(0); final ValueHolder hookResult = new ValueHolder<>(0); final CommitHookCallback theHook = new CommitHookCallback(){ @@ -1138,7 +1139,7 @@ public class Tester1 implements Runnable { affirm( 5 == counter.value ); hookResult.value = SQLITE_ERROR; int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;"); - affirm( SQLITE_CONSTRAINT == rc ); + affirm( SQLITE_CONSTRAINT_COMMITHOOK == rc ); affirm( 6 == counter.value ); sqlite3_close_v2(db); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index ffbc695242..dcd475ea68 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -1253,4 +1253,105 @@ public final class Sqlite implements AutoCloseable { } checkRc( CApi.sqlite3_busy_handler(thisDb(), bhc) ); } + + public interface CommitHook { + /** + Must behave as documented for the C-level sqlite3_commit_hook() + callback. If it throws, the exception is translated into + a db-level error. + */ + int call(); + } + + /** + A level of indirection to permit setCommitHook() to have similar + semantics as the C API, returning the previous hook. The caveat + is that if the low-level API is used to install a hook, it will + have a different hook type than Sqlite.CommitHook so + setCommitHook() will return null instead of that object. + */ + private static class CommitHookProxy + implements org.sqlite.jni.capi.CommitHookCallback { + final CommitHook commitHook; + CommitHookProxy(CommitHook ch){ + this.commitHook = ch; + } + @Override public int call(){ + return commitHook.call(); + } + } + + /** + Analog to sqlite3_commit_hook(). Returns the previous hook, if + any (else null). Throws if this db is closed. + + Minor caveat: if a commit hook is set on this object's underlying + db handle using the lower-level SQLite API, this function may + return null when replacing it, despite there being a hook, + because it will have a different callback type. So long as the + handle is only manipulated via the high-level API, this caveat + does not apply. + */ + CommitHook setCommitHook( CommitHook c ){ + CommitHookProxy chp = null; + if( null!=c ){ + chp = new CommitHookProxy(c); + } + final org.sqlite.jni.capi.CommitHookCallback rv = + CApi.sqlite3_commit_hook(thisDb(), chp); + return (rv instanceof CommitHookProxy) + ? ((CommitHookProxy)rv).commitHook + : null; + } + + + public interface RollbackHook { + /** + Must behave as documented for the C-level sqlite3_rollback_hook() + callback. If it throws, the exception is translated into + a db-level error. + */ + void call(); + } + + /** + A level of indirection to permit setRollbackHook() to have similar + semantics as the C API, returning the previous hook. The caveat + is that if the low-level API is used to install a hook, it will + have a different hook type than Sqlite.RollbackHook so + setRollbackHook() will return null instead of that object. + */ + private static class RollbackHookProxy + implements org.sqlite.jni.capi.RollbackHookCallback { + final RollbackHook rollbackHook; + RollbackHookProxy(RollbackHook ch){ + this.rollbackHook = ch; + } + @Override public void call(){rollbackHook.call();} + } + + /** + Analog to sqlite3_rollback_hook(). Returns the previous hook, if + any (else null). Throws if this db is closed. + + Minor caveat: if a rollback hook is set on this object's underlying + db handle using the lower-level SQLite API, this function may + return null when replacing it, despite there being a hook, + because it will have a different callback type. So long as the + handle is only manipulated via the high-level API, this caveat + does not apply. + */ + RollbackHook setRollbackHook( RollbackHook c ){ + RollbackHookProxy chp = null; + if( null!=c ){ + chp = new RollbackHookProxy(c); + } + final org.sqlite.jni.capi.RollbackHookCallback rv = + CApi.sqlite3_rollback_hook(thisDb(), chp); + return (rv instanceof RollbackHookProxy) + ? ((RollbackHookProxy)rv).rollbackHook + : null; + } + + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 3a00c0953f..56ea35ef1f 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -737,6 +737,87 @@ public class Tester2 implements Runnable { } } + private void testCommitHook(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + final ValueHolder hookResult = new ValueHolder<>(0); + final Sqlite.CommitHook theHook = new Sqlite.CommitHook(){ + @Override public int call(){ + ++counter.value; + return hookResult.value; + } + }; + Sqlite.CommitHook oldHook = db.setCommitHook(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 = db.setCommitHook(theHook); + affirm( theHook == oldHook ); + execSql(db, "BEGIN; update t set a='e' where a='d'; COMMIT;"); + affirm( 4 == counter.value ); + oldHook = db.setCommitHook(null); + affirm( theHook == oldHook ); + execSql(db, "BEGIN; update t set a='f' where a='e'; COMMIT;"); + affirm( 4 == counter.value ); + oldHook = db.setCommitHook(null); + affirm( null == oldHook ); + execSql(db, "BEGIN; update t set a='g' where a='f'; COMMIT;"); + affirm( 4 == counter.value ); + + final Sqlite.CommitHook newHook = new Sqlite.CommitHook(){ + @Override public int call(){return 0;} + }; + oldHook = db.setCommitHook(newHook); + affirm( null == oldHook ); + execSql(db, "BEGIN; update t set a='h' where a='g'; COMMIT;"); + affirm( 4 == counter.value ); + oldHook = db.setCommitHook(theHook); + affirm( newHook == oldHook ); + execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;"); + affirm( 5 == counter.value ); + hookResult.value = CApi.SQLITE_ERROR; + int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;"); + affirm( CApi.SQLITE_CONSTRAINT_COMMITHOOK == rc ); + affirm( 6 == counter.value ); + db.close(); + } + + private void testRollbackHook(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + final Sqlite.RollbackHook theHook = new Sqlite.RollbackHook(){ + @Override public void call(){ + ++counter.value; + } + }; + Sqlite.RollbackHook oldHook = db.setRollbackHook(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 Sqlite.RollbackHook newHook = new Sqlite.RollbackHook(){ + @Override public void call(){} + }; + oldHook = db.setRollbackHook(newHook); + affirm( theHook == oldHook ); + execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;"); + affirm( 1 == counter.value ); + oldHook = db.setRollbackHook(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 ); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 0cdcd1cfcd..68dcbace48 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sbusy-handler\ssupport\sto\sJNI\swrapper1. -D 2023-11-05T00:02:47.384 +C Add\scommit/rollback\shook\ssupport\sto\sJNI\swrapper1. +D 2023-11-05T00:48:43.424 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 931a7320f5b5745034b4fd61027ea7cc29559856e6da613e4fdcf01ef102e710 +F ext/jni/src/c/sqlite3-jni.c e24804e86759c0680064aacc46ab901d9b2b1a44eba312bcc9a387f15f044d12 F ext/jni/src/c/sqlite3-jni.h 1c45fd4689cec42f3d84d2fee41bb494016a12fcb5fd80291095590666a14015 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -255,7 +255,7 @@ F ext/jni/src/org/sqlite/jni/capi/CApi.java 4043d709626079cce6d524ef49122b934c04 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab -F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 29c002f3c638cc80f7db1594564a262d1beb32637824c3dca2d60a224d1f71d7 +F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 482f53dfec9e3ac2a9070d3fceebd56250932aaaf7c4f5bc8de29fc011416e0c F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4 F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33 F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 4bb5e62907a422a80a0fccbcb83085e9163c2c245451312a62c7550a45d16683 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 909ebd23111762c878116ebacf73a848c8323fb46e8128eb3d99a85d48905444 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java c930ca964f605ba8f175d3b0c85099d7f93069b59bf825929c9eef9e68ac96c5 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 782bb185ffc629cdabbd624565a52ed9b4b1b2d773b8b1d84476d91cbf94827d F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 6f5fae3c3827ca42ef124c319b24907483aadda69b7453173f7807e0a94f33dd +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java ab1236dd65b4f90db729c88c71382b14aa179095f8b8e4b50835125bd0072f9e F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe -R 2dabe33af17a981e8c8323ecd84b4487 +P dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20 +R f0002b14be80bf0bcecc7fa19a1e63af U stephan -Z c2d53a448e9f555de7ff26068d4eba40 +Z 507dddf857173269602bfa9033ce1fa7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 97de8be89b..ba526bfc7b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20 \ No newline at end of file +ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8 \ No newline at end of file From 0ee7ae72a1c7993878bb46df377db6583e2c4ecc Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 01:14:07 +0000 Subject: [PATCH 11/55] Add update-hook support to JNI wrapper1. FossilOrigin-Name: 6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618 --- .../sqlite/jni/capi/RollbackHookCallback.java | 5 +- .../sqlite/jni/capi/UpdateHookCallback.java | 3 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 84 +++++++++++++++++++ .../src/org/sqlite/jni/wrapper1/Tester2.java | 56 ++++++++++++- manifest | 18 ++-- manifest.uuid | 2 +- 6 files changed, 153 insertions(+), 15 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java index 5ce17e718a..cf9c4b6e7a 100644 --- a/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java @@ -18,8 +18,9 @@ package org.sqlite.jni.capi; */ public interface RollbackHookCallback extends CallbackProxy { /** - Works as documented for the C-level sqlite3_rollback_hook() - callback. + Must function as documented for the C-level sqlite3_rollback_hook() + callback. If it throws, the exception is translated into + a db-level error. */ void call(); } diff --git a/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java index 33d72a5dd2..e3d491f67e 100644 --- a/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java @@ -19,7 +19,8 @@ package org.sqlite.jni.capi; public interface UpdateHookCallback extends CallbackProxy { /** Must function as described for the C-level sqlite3_update_hook() - callback. + callback. If it throws, the exception is translated into + a db-level error. */ void call(int opId, String dbName, String tableName, long rowId); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index dcd475ea68..324f65ae29 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -112,6 +112,42 @@ public final class Sqlite implements AutoCloseable { public static final int BUSY = CApi.SQLITE_BUSY; public static final int LOCKED = CApi.SQLITE_LOCKED; + public static final int DENY = CApi.SQLITE_DENY; + public static final int IGNORE = CApi.SQLITE_IGNORE; + public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX; + public static final int CREATE_TABLE = CApi.SQLITE_CREATE_TABLE; + public static final int CREATE_TEMP_INDEX = CApi.SQLITE_CREATE_TEMP_INDEX; + public static final int CREATE_TEMP_TABLE = CApi.SQLITE_CREATE_TEMP_TABLE; + public static final int CREATE_TEMP_TRIGGER = CApi.SQLITE_CREATE_TEMP_TRIGGER; + public static final int CREATE_TEMP_VIEW = CApi.SQLITE_CREATE_TEMP_VIEW; + public static final int CREATE_TRIGGER = CApi.SQLITE_CREATE_TRIGGER; + public static final int CREATE_VIEW = CApi.SQLITE_CREATE_VIEW; + public static final int DELETE = CApi.SQLITE_DELETE; + public static final int DROP_INDEX = CApi.SQLITE_DROP_INDEX; + public static final int DROP_TABLE = CApi.SQLITE_DROP_TABLE; + public static final int DROP_TEMP_INDEX = CApi.SQLITE_DROP_TEMP_INDEX; + public static final int DROP_TEMP_TABLE = CApi.SQLITE_DROP_TEMP_TABLE; + public static final int DROP_TEMP_TRIGGER = CApi.SQLITE_DROP_TEMP_TRIGGER; + public static final int DROP_TEMP_VIEW = CApi.SQLITE_DROP_TEMP_VIEW; + public static final int DROP_TRIGGER = CApi.SQLITE_DROP_TRIGGER; + public static final int DROP_VIEW = CApi.SQLITE_DROP_VIEW; + public static final int INSERT = CApi.SQLITE_INSERT; + public static final int PRAGMA = CApi.SQLITE_PRAGMA; + public static final int READ = CApi.SQLITE_READ; + public static final int SELECT = CApi.SQLITE_SELECT; + public static final int TRANSACTION = CApi.SQLITE_TRANSACTION; + public static final int UPDATE = CApi.SQLITE_UPDATE; + public static final int ATTACH = CApi.SQLITE_ATTACH; + public static final int DETACH = CApi.SQLITE_DETACH; + public static final int ALTER_TABLE = CApi.SQLITE_ALTER_TABLE; + public static final int REINDEX = CApi.SQLITE_REINDEX; + public static final int ANALYZE = CApi.SQLITE_ANALYZE; + public static final int CREATE_VTABLE = CApi.SQLITE_CREATE_VTABLE; + public static final int DROP_VTABLE = CApi.SQLITE_DROP_VTABLE; + public static final int FUNCTION = CApi.SQLITE_FUNCTION; + public static final int SAVEPOINT = CApi.SQLITE_SAVEPOINT; + public static final int RECURSIVE = CApi.SQLITE_RECURSIVE; + //! Used only by the open() factory functions. private Sqlite(sqlite3 db){ this.db = db; @@ -1353,5 +1389,53 @@ public final class Sqlite implements AutoCloseable { : null; } + public interface UpdateHook { + /** + Must function as described for the C-level sqlite3_update_hook() + callback. + */ + void call(int opId, String dbName, String tableName, long rowId); + } + + /** + A level of indirection to permit setUpdateHook() to have similar + semantics as the C API, returning the previous hook. The caveat + is that if the low-level API is used to install a hook, it will + have a different hook type than Sqlite.UpdateHook so + setUpdateHook() will return null instead of that object. + */ + private static class UpdateHookProxy + implements org.sqlite.jni.capi.UpdateHookCallback { + final UpdateHook updateHook; + UpdateHookProxy(UpdateHook ch){ + this.updateHook = ch; + } + @Override public void call(int opId, String dbName, String tableName, long rowId){ + updateHook.call(opId, dbName, tableName, rowId); + } + } + + /** + Analog to sqlite3_update_hook(). Returns the previous hook, if + any (else null). Throws if this db is closed. + + Minor caveat: if a update hook is set on this object's underlying + db handle using the lower-level SQLite API, this function may + return null when replacing it, despite there being a hook, + because it will have a different callback type. So long as the + handle is only manipulated via the high-level API, this caveat + does not apply. + */ + UpdateHook setUpdateHook( UpdateHook c ){ + UpdateHookProxy chp = null; + if( null!=c ){ + chp = new UpdateHookProxy(c); + } + final org.sqlite.jni.capi.UpdateHookCallback rv = + CApi.sqlite3_update_hook(thisDb(), chp); + return (rv instanceof UpdateHookProxy) + ? ((UpdateHookProxy)rv).updateHook + : null; + } } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 56ea35ef1f..fd8fb69b7a 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -133,6 +133,9 @@ public class Tester2 implements Runnable { Executes all SQL statements in the given string. If throwOnError is true then it will throw for any prepare/step errors, else it will return the corresponding non-0 result code. + + TODO: reimplement this in the high-level API once it has the + multi-prepare capability. */ public static int execSql(Sqlite dbw, boolean throwOnError, String sql){ final sqlite3 db = dbw.nativeHandle(); @@ -163,7 +166,7 @@ public class Tester2 implements Runnable { } CApi.sqlite3_finalize(stmt); affirm(0 == stmt.getNativePointer()); - if(CApi.SQLITE_DONE!=rc){ + if(Sqlite.DONE!=rc){ break; } } @@ -181,7 +184,7 @@ public class Tester2 implements Runnable { @SingleThreadOnly /* because it's thread-agnostic */ private void test1(){ - affirm(CApi.sqlite3_libversion_number() == CApi.SQLITE_VERSION_NUMBER); + affirm(Sqlite.libVersionNumber() == CApi.SQLITE_VERSION_NUMBER); } /* Copy/paste/rename this to add new tests. */ @@ -818,6 +821,55 @@ public class Tester2 implements Runnable { db.close(); } + private void testUpdateHook(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + final ValueHolder expectedOp = new ValueHolder<>(0); + final Sqlite.UpdateHook theHook = new Sqlite.UpdateHook(){ + @Override + public void call(int opId, String dbName, String tableName, long rowId){ + ++counter.value; + if( 0!=expectedOp.value ){ + affirm( expectedOp.value == opId ); + } + } + }; + Sqlite.UpdateHook oldHook = db.setUpdateHook(theHook); + affirm( null == oldHook ); + expectedOp.value = Sqlite.INSERT; + execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')"); + affirm( 3 == counter.value ); + expectedOp.value = Sqlite.UPDATE; + execSql(db, "update t set a='d' where a='c';"); + affirm( 4 == counter.value ); + oldHook = db.setUpdateHook(theHook); + affirm( theHook == oldHook ); + expectedOp.value = Sqlite.DELETE; + execSql(db, "DELETE FROM t where a='d'"); + affirm( 5 == counter.value ); + oldHook = db.setUpdateHook(null); + affirm( theHook == oldHook ); + execSql(db, "update t set a='e' where a='b';"); + affirm( 5 == counter.value ); + oldHook = db.setUpdateHook(null); + affirm( null == oldHook ); + + final Sqlite.UpdateHook newHook = new Sqlite.UpdateHook(){ + @Override public void call(int opId, String dbName, String tableName, long rowId){ + } + }; + oldHook = db.setUpdateHook(newHook); + affirm( null == oldHook ); + execSql(db, "update t set a='h' where a='a'"); + affirm( 5 == counter.value ); + oldHook = db.setUpdateHook(theHook); + affirm( newHook == oldHook ); + expectedOp.value = Sqlite.UPDATE; + execSql(db, "update t set a='i' where a='h'"); + affirm( 6 == counter.value ); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 68dcbace48..3ee436df87 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\scommit/rollback\shook\ssupport\sto\sJNI\swrapper1. -D 2023-11-05T00:48:43.424 +C Add\supdate-hook\ssupport\sto\sJNI\swrapper1. +D 2023-11-05T01:14:07.152 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -264,14 +264,14 @@ F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java aca8f9fa72e3b6602bc9 F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java 819d938e26208adde17ca4b7ddde1d8cd6915b6ab7b708249a9787beca6bd6b6 F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f -F ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java 105e324d09c207100485e7667ad172e64322c62426bb49b547e9b0dc9c33f5f0 +F ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java e172210a2080e851ebb694c70e9f0bf89284237795e38710a7f5f1b61e3f6787 F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385155fa3b8011a5cca0bb3c28468c7131c1a5 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f F ext/jni/src/org/sqlite/jni/capi/Tester1.java 909ebd23111762c878116ebacf73a848c8323fb46e8128eb3d99a85d48905444 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 -F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 +F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 782bb185ffc629cdabbd624565a52ed9b4b1b2d773b8b1d84476d91cbf94827d +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 12f55248d500c0cf4148757adb442303831632edaa738a41d82708643ba42418 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java ab1236dd65b4f90db729c88c71382b14aa179095f8b8e4b50835125bd0072f9e +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 4cb3bebcd44f4289fa8075477583b6c508832288f7b18d6101d2ec23309ee4cf F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20 -R f0002b14be80bf0bcecc7fa19a1e63af +P ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8 +R 100ace4e28cdce95fe3bed6faf77a591 U stephan -Z 507dddf857173269602bfa9033ce1fa7 +Z dbd53c8956790cde47b0f616fa6677f5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ba526bfc7b..e37ae0477c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8 \ No newline at end of file +6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618 \ No newline at end of file From 9a265899409da5ecc374f97fc3cd67706da69c4b Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 01:39:29 +0000 Subject: [PATCH 12/55] Add progress-handler support to JNI wrapper1. Correct the return type of the extended_result_codes() JNI binding and expose it to wrapper1. FossilOrigin-Name: 6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88 --- ext/jni/src/c/sqlite3-jni.c | 8 +- ext/jni/src/c/sqlite3-jni.h | 4 +- ext/jni/src/org/sqlite/jni/capi/CApi.java | 2 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 162 +++++++++++------- .../sqlite/jni/wrapper1/SqliteException.java | 2 +- .../src/org/sqlite/jni/wrapper1/Tester2.java | 18 ++ manifest | 22 +-- manifest.uuid | 2 +- 8 files changed, 142 insertions(+), 78 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 0d60e49d13..c530651cd7 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -3596,12 +3596,14 @@ S3JniApi(sqlite3_normalized_sql(),jstring,1normalized_1sql)( #endif } -S3JniApi(sqlite3_extended_result_codes(),jboolean,1extended_1result_1codes)( +S3JniApi(sqlite3_extended_result_codes(),jint,1extended_1result_1codes)( JniArgsEnvClass, jobject jpDb, jboolean onoff ){ sqlite3 * const pDb = PtrGet_sqlite3(jpDb); - int const rc = pDb ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0) : 0; - return rc ? JNI_TRUE : JNI_FALSE; + int const rc = pDb + ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0) + : SQLITE_MISUSE; + return rc; } S3JniApi(sqlite3_finalize(),jint,1finalize)( diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index e4393ddd8b..a1097fe57a 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1402,9 +1402,9 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1errcode /* * Class: org_sqlite_jni_capi_CApi * Method: sqlite3_extended_result_codes - * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)Z + * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)I */ -JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes +JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes (JNIEnv *, jclass, jobject, jboolean); /* diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 79568e74ad..f1d4def500 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -890,7 +890,7 @@ public final class CApi { return sqlite3_extended_errcode(db.getNativePointer()); } - public static native boolean sqlite3_extended_result_codes( + public static native int sqlite3_extended_result_codes( @NotNull sqlite3 db, boolean on ); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 324f65ae29..d9b5a17c20 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -213,61 +213,6 @@ public final class Sqlite implements AutoCloseable { return CApi.sqlite3_sourceid(); } - - /** - Output object for use with status() and libStatus(). - */ - public static final class Status { - /** The current value for the requested status() or libStatus() metric. */ - long current; - /** The peak value for the requested status() or libStatus() metric. */ - long peak; - }; - - /** - As per sqlite3_status64(), but returns its current and high-water - results as a Status object. Throws if the first argument is - not one of the STATUS_... constants. - */ - public static Status libStatus(int op, boolean resetStats){ - org.sqlite.jni.capi.OutputPointer.Int64 pCurrent = - new org.sqlite.jni.capi.OutputPointer.Int64(); - org.sqlite.jni.capi.OutputPointer.Int64 pHighwater = - new org.sqlite.jni.capi.OutputPointer.Int64(); - checkRc2( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) ); - final Status s = new Status(); - s.current = pCurrent.value; - s.peak = pHighwater.value; - return s; - } - - /** - As per sqlite3_status64(), but returns its current and high-water - results as a Status object. Throws if the first argument is - not one of the DBSTATUS_... constants or on any other misuse. - */ - public Status status(int op, boolean resetStats){ - org.sqlite.jni.capi.OutputPointer.Int32 pCurrent = - new org.sqlite.jni.capi.OutputPointer.Int32(); - org.sqlite.jni.capi.OutputPointer.Int32 pHighwater = - new org.sqlite.jni.capi.OutputPointer.Int32(); - checkRc( CApi.sqlite3_db_status(thisDb(), op, pCurrent, pHighwater, resetStats) ); - final Status s = new Status(); - s.current = pCurrent.value; - s.peak = pHighwater.value; - return s; - } - - @Override public void close(){ - if(null!=this.db){ - synchronized(nativeToWrapper){ - nativeToWrapper.remove(this.db); - } - this.db.close(); - this.db = null; - } - } - /** Returns the value of the native library's build-time value of the SQLITE_THREADSAFE build option. @@ -325,6 +270,61 @@ public final class Sqlite implements AutoCloseable { return 0==CApi.sqlite3_strlike(glob, txt, escChar); } + /** + Output object for use with status() and libStatus(). + */ + public static final class Status { + /** The current value for the requested status() or libStatus() metric. */ + long current; + /** The peak value for the requested status() or libStatus() metric. */ + long peak; + }; + + /** + As per sqlite3_status64(), but returns its current and high-water + results as a Status object. Throws if the first argument is + not one of the STATUS_... constants. + */ + public static Status libStatus(int op, boolean resetStats){ + org.sqlite.jni.capi.OutputPointer.Int64 pCurrent = + new org.sqlite.jni.capi.OutputPointer.Int64(); + org.sqlite.jni.capi.OutputPointer.Int64 pHighwater = + new org.sqlite.jni.capi.OutputPointer.Int64(); + checkRc2( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) ); + final Status s = new Status(); + s.current = pCurrent.value; + s.peak = pHighwater.value; + return s; + } + + /** + As per sqlite3_db_status(), but returns its current and + high-water results as a Status object. Throws if the first + argument is not one of the DBSTATUS_... constants or on any other + misuse. + */ + public Status status(int op, boolean resetStats){ + org.sqlite.jni.capi.OutputPointer.Int32 pCurrent = + new org.sqlite.jni.capi.OutputPointer.Int32(); + org.sqlite.jni.capi.OutputPointer.Int32 pHighwater = + new org.sqlite.jni.capi.OutputPointer.Int32(); + checkRc( CApi.sqlite3_db_status(thisDb(), op, pCurrent, pHighwater, resetStats) ); + final Status s = new Status(); + s.current = pCurrent.value; + s.peak = pHighwater.value; + return s; + } + + @Override public void close(){ + if(null!=this.db){ + synchronized(nativeToWrapper){ + nativeToWrapper.remove(this.db); + } + this.db.close(); + this.db = null; + } + } + /** Returns this object's underlying native db handle, or null if this instance has been closed. This is very specifically not @@ -379,6 +379,19 @@ public final class Sqlite implements AutoCloseable { } } + /** + Toggles the use of extended result codes on or off. By default + they are turned off, but they can be enabled by default by + including the OPEN_EXRESCODE flag when opening a database. + + Because this API reports db-side errors using exceptions, + enabling this may change the values returned by + SqliteException.errcode(). + */ + public void useExtendedResultCodes(boolean on){ + checkRc( CApi.sqlite3_extended_result_codes(thisDb(), on) ); + } + /** prepFlags must be 0 or a bitmask of the PREPARE_... constants. @@ -1278,7 +1291,7 @@ public final class Sqlite implements AutoCloseable { Analog to sqlite3_busy_handler(). If b is null then any current handler is cleared. */ - void setBusyHandler( BusyHandler b ){ + public void setBusyHandler( BusyHandler b ){ org.sqlite.jni.capi.BusyHandlerCallback bhc = null; if( null!=b ){ bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){ @@ -1328,7 +1341,7 @@ public final class Sqlite implements AutoCloseable { handle is only manipulated via the high-level API, this caveat does not apply. */ - CommitHook setCommitHook( CommitHook c ){ + public CommitHook setCommitHook( CommitHook c ){ CommitHookProxy chp = null; if( null!=c ){ chp = new CommitHookProxy(c); @@ -1377,7 +1390,7 @@ public final class Sqlite implements AutoCloseable { handle is only manipulated via the high-level API, this caveat does not apply. */ - RollbackHook setRollbackHook( RollbackHook c ){ + public RollbackHook setRollbackHook( RollbackHook c ){ RollbackHookProxy chp = null; if( null!=c ){ chp = new RollbackHookProxy(c); @@ -1426,7 +1439,7 @@ public final class Sqlite implements AutoCloseable { handle is only manipulated via the high-level API, this caveat does not apply. */ - UpdateHook setUpdateHook( UpdateHook c ){ + public UpdateHook setUpdateHook( UpdateHook c ){ UpdateHookProxy chp = null; if( null!=c ){ chp = new UpdateHookProxy(c); @@ -1438,4 +1451,35 @@ public final class Sqlite implements AutoCloseable { : null; } + + /** + Callback interface for use with setProgressHandler(). + */ + public interface ProgressHandler { + /** + Must behave as documented for the C-level sqlite3_progress_handler() + callback. If it throws, the exception is translated into + a db-level error. + */ + int call(); + } + + /** + Analog to sqlite3_progress_handler(), sets the current progress + handler or clears it if p is null. + + Note that this API, in contrast to setUpdateHook(), + setRollbackHook(), and setCommitHook(), cannot return the + previous handler. That inconsistency is part of the lower-level C + API. + */ + public void setProgressHandler( int n, ProgressHandler p ){ + org.sqlite.jni.capi.ProgressHandlerCallback phc = null; + if( null!=p ){ + phc = new org.sqlite.jni.capi.ProgressHandlerCallback(){ + @Override public int call(){ return p.call(); } + }; + } + CApi.sqlite3_progress_handler( thisDb(), n, phc ); + } } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java index 09fa02a2ca..9b4440f190 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java @@ -50,7 +50,7 @@ public final class SqliteException extends java.lang.RuntimeException { /** Records the current error state of db (which must not be null and - must refer to an opened db object). Note that this does NOT close + must refer to an opened db object). Note that this does not close the db. Design note: closing the db on error is really only useful during diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index fd8fb69b7a..1af2c8c5d1 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -870,6 +870,24 @@ public class Tester2 implements Runnable { db.close(); } + private void testProgress(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + db.setProgressHandler(1, new Sqlite.ProgressHandler(){ + @Override public int call(){ + ++counter.value; + return 0; + } + }); + execSql(db, "SELECT 1; SELECT 2;"); + affirm( counter.value > 0 ); + int nOld = counter.value; + db.setProgressHandler(0, null); + execSql(db, "SELECT 1; SELECT 2;"); + affirm( nOld == counter.value ); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 3ee436df87..82936f69b9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\supdate-hook\ssupport\sto\sJNI\swrapper1. -D 2023-11-05T01:14:07.152 +C Add\sprogress-handler\ssupport\sto\sJNI\swrapper1.\sCorrect\sthe\sreturn\stype\sof\sthe\sextended_result_codes()\sJNI\sbinding\sand\sexpose\sit\sto\swrapper1. +D 2023-11-05T01:39:29.450 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,8 +241,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c e24804e86759c0680064aacc46ab901d9b2b1a44eba312bcc9a387f15f044d12 -F ext/jni/src/c/sqlite3-jni.h 1c45fd4689cec42f3d84d2fee41bb494016a12fcb5fd80291095590666a14015 +F ext/jni/src/c/sqlite3-jni.c b98d822a35ef4438023c3c14816b5ac17bdbd23bc838ff80b6463c3146a75d14 +F ext/jni/src/c/sqlite3-jni.h 03f66d3b43359dacd7c2c9407d78274dbdb027bc7610985011bf2b462222414e F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 4043d709626079cce6d524ef49122b934c043022bd88bc1e72eb697ac8df86e7 +F ext/jni/src/org/sqlite/jni/capi/CApi.java a6d4fdd35e4fcfe95c61e343eb389cfaab3d5166e9670730aef14240a982b97b F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 12f55248d500c0cf4148757adb442303831632edaa738a41d82708643ba42418 -F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 4cb3bebcd44f4289fa8075477583b6c508832288f7b18d6101d2ec23309ee4cf +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 923c885609ca9e6793636fc17787d0058c80ce1d7ba5a69eb40e68cc299892d1 +F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 822cf3d66beb1efcac1792c8652cbebb80ae998275a33337de46fde1670e0008 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8 -R 100ace4e28cdce95fe3bed6faf77a591 +P 6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618 +R dafa52fdba2c999e04b851e5ec6214ab U stephan -Z dbd53c8956790cde47b0f616fa6677f5 +Z 824d9a7ed24ad4091f85bc7e5264c033 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e37ae0477c..7f82e1d85b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618 \ No newline at end of file +6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88 \ No newline at end of file From 88c90a793ef80560b90a37802c06135c5bef3617 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 01:55:20 +0000 Subject: [PATCH 13/55] Add authorizer support to JNI wrapper1. FossilOrigin-Name: 773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0 --- .../sqlite/jni/capi/AuthorizerCallback.java | 3 +- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 3 + .../src/org/sqlite/jni/wrapper1/Sqlite.java | 139 +++++++++++++++++- .../src/org/sqlite/jni/wrapper1/Tester2.java | 24 +++ manifest | 18 +-- manifest.uuid | 2 +- 6 files changed, 174 insertions(+), 15 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java b/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java index ce7c6fca6d..298e3a5900 100644 --- a/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java @@ -20,7 +20,8 @@ import org.sqlite.jni.annotation.*; public interface AuthorizerCallback extends CallbackProxy { /** Must function as described for the C-level - sqlite3_set_authorizer() callback. + sqlite3_set_authorizer() callback. If it throws, the error is + converted to a db-level error and the exception is suppressed. */ int call(int opId, @Nullable String s1, @Nullable String s2, @Nullable String s3, @Nullable String s4); diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 4a8ceb1812..fb53196d26 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1358,6 +1358,9 @@ public class Tester1 implements Runnable { authRc.value = SQLITE_DENY; int rc = execSql(db, false, "UPDATE t SET a=2"); affirm( SQLITE_AUTH==rc ); + sqlite3_set_authorizer(db, null); + rc = execSql(db, false, "UPDATE t SET a=2"); + affirm( 0==rc ); // TODO: expand these tests considerably sqlite3_close(db); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index d9b5a17c20..cf18277329 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -29,6 +29,111 @@ import org.sqlite.jni.capi.OutputPointer; public final class Sqlite implements AutoCloseable { private sqlite3 db; + public static final int OK = CApi.SQLITE_OK; + public static final int ERROR = CApi.SQLITE_ERROR; + public static final int INTERNAL = CApi.SQLITE_INTERNAL; + public static final int PERM = CApi.SQLITE_PERM; + public static final int ABORT = CApi.SQLITE_ABORT; + public static final int BUSY = CApi.SQLITE_BUSY; + public static final int LOCKED = CApi.SQLITE_LOCKED; + public static final int NOMEM = CApi.SQLITE_NOMEM; + public static final int READONLY = CApi.SQLITE_READONLY; + public static final int INTERRUPT = CApi.SQLITE_INTERRUPT; + public static final int IOERR = CApi.SQLITE_IOERR; + public static final int CORRUPT = CApi.SQLITE_CORRUPT; + public static final int NOTFOUND = CApi.SQLITE_NOTFOUND; + public static final int FULL = CApi.SQLITE_FULL; + public static final int CANTOPEN = CApi.SQLITE_CANTOPEN; + public static final int PROTOCOL = CApi.SQLITE_PROTOCOL; + public static final int EMPTY = CApi.SQLITE_EMPTY; + public static final int SCHEMA = CApi.SQLITE_SCHEMA; + public static final int TOOBIG = CApi.SQLITE_TOOBIG; + public static final int CONSTRAINT = CApi. SQLITE_CONSTRAINT; + public static final int MISMATCH = CApi.SQLITE_MISMATCH; + public static final int MISUSE = CApi.SQLITE_MISUSE; + public static final int NOLFS = CApi.SQLITE_NOLFS; + public static final int AUTH = CApi.SQLITE_AUTH; + public static final int FORMAT = CApi.SQLITE_FORMAT; + public static final int RANGE = CApi.SQLITE_RANGE; + public static final int NOTADB = CApi.SQLITE_NOTADB; + public static final int NOTICE = CApi.SQLITE_NOTICE; + public static final int WARNING = CApi.SQLITE_WARNING; + public static final int ROW = CApi.SQLITE_ROW; + public static final int DONE = CApi.SQLITE_DONE; + public static final int ERROR_MISSING_COLLSEQ = CApi.SQLITE_ERROR_MISSING_COLLSEQ; + public static final int ERROR_RETRY = CApi.SQLITE_ERROR_RETRY; + public static final int ERROR_SNAPSHOT = CApi.SQLITE_ERROR_SNAPSHOT; + public static final int IOERR_READ = CApi.SQLITE_IOERR_READ; + public static final int IOERR_SHORT_READ = CApi.SQLITE_IOERR_SHORT_READ; + public static final int IOERR_WRITE = CApi.SQLITE_IOERR_WRITE; + public static final int IOERR_FSYNC = CApi.SQLITE_IOERR_FSYNC; + public static final int IOERR_DIR_FSYNC = CApi.SQLITE_IOERR_DIR_FSYNC; + public static final int IOERR_TRUNCATE = CApi.SQLITE_IOERR_TRUNCATE; + public static final int IOERR_FSTAT = CApi.SQLITE_IOERR_FSTAT; + public static final int IOERR_UNLOCK = CApi.SQLITE_IOERR_UNLOCK; + public static final int IOERR_RDLOCK = CApi.SQLITE_IOERR_RDLOCK; + public static final int IOERR_DELETE = CApi.SQLITE_IOERR_DELETE; + public static final int IOERR_BLOCKED = CApi.SQLITE_IOERR_BLOCKED; + public static final int IOERR_NOMEM = CApi.SQLITE_IOERR_NOMEM; + public static final int IOERR_ACCESS = CApi.SQLITE_IOERR_ACCESS; + public static final int IOERR_CHECKRESERVEDLOCK = CApi.SQLITE_IOERR_CHECKRESERVEDLOCK; + public static final int IOERR_LOCK = CApi.SQLITE_IOERR_LOCK; + public static final int IOERR_CLOSE = CApi.SQLITE_IOERR_CLOSE; + public static final int IOERR_DIR_CLOSE = CApi.SQLITE_IOERR_DIR_CLOSE; + public static final int IOERR_SHMOPEN = CApi.SQLITE_IOERR_SHMOPEN; + public static final int IOERR_SHMSIZE = CApi.SQLITE_IOERR_SHMSIZE; + public static final int IOERR_SHMLOCK = CApi.SQLITE_IOERR_SHMLOCK; + public static final int IOERR_SHMMAP = CApi.SQLITE_IOERR_SHMMAP; + public static final int IOERR_SEEK = CApi.SQLITE_IOERR_SEEK; + public static final int IOERR_DELETE_NOENT = CApi.SQLITE_IOERR_DELETE_NOENT; + public static final int IOERR_MMAP = CApi.SQLITE_IOERR_MMAP; + public static final int IOERR_GETTEMPPATH = CApi.SQLITE_IOERR_GETTEMPPATH; + public static final int IOERR_CONVPATH = CApi.SQLITE_IOERR_CONVPATH; + public static final int IOERR_VNODE = CApi.SQLITE_IOERR_VNODE; + public static final int IOERR_AUTH = CApi.SQLITE_IOERR_AUTH; + public static final int IOERR_BEGIN_ATOMIC = CApi.SQLITE_IOERR_BEGIN_ATOMIC; + public static final int IOERR_COMMIT_ATOMIC = CApi.SQLITE_IOERR_COMMIT_ATOMIC; + public static final int IOERR_ROLLBACK_ATOMIC = CApi.SQLITE_IOERR_ROLLBACK_ATOMIC; + public static final int IOERR_DATA = CApi.SQLITE_IOERR_DATA; + public static final int IOERR_CORRUPTFS = CApi.SQLITE_IOERR_CORRUPTFS; + public static final int LOCKED_SHAREDCACHE = CApi.SQLITE_LOCKED_SHAREDCACHE; + public static final int LOCKED_VTAB = CApi.SQLITE_LOCKED_VTAB; + public static final int BUSY_RECOVERY = CApi.SQLITE_BUSY_RECOVERY; + public static final int BUSY_SNAPSHOT = CApi.SQLITE_BUSY_SNAPSHOT; + public static final int BUSY_TIMEOUT = CApi.SQLITE_BUSY_TIMEOUT; + public static final int CANTOPEN_NOTEMPDIR = CApi.SQLITE_CANTOPEN_NOTEMPDIR; + public static final int CANTOPEN_ISDIR = CApi.SQLITE_CANTOPEN_ISDIR; + public static final int CANTOPEN_FULLPATH = CApi.SQLITE_CANTOPEN_FULLPATH; + public static final int CANTOPEN_CONVPATH = CApi.SQLITE_CANTOPEN_CONVPATH; + public static final int CANTOPEN_SYMLINK = CApi.SQLITE_CANTOPEN_SYMLINK; + public static final int CORRUPT_VTAB = CApi.SQLITE_CORRUPT_VTAB; + public static final int CORRUPT_SEQUENCE = CApi.SQLITE_CORRUPT_SEQUENCE; + public static final int CORRUPT_INDEX = CApi.SQLITE_CORRUPT_INDEX; + public static final int READONLY_RECOVERY = CApi.SQLITE_READONLY_RECOVERY; + public static final int READONLY_CANTLOCK = CApi.SQLITE_READONLY_CANTLOCK; + public static final int READONLY_ROLLBACK = CApi.SQLITE_READONLY_ROLLBACK; + public static final int READONLY_DBMOVED = CApi.SQLITE_READONLY_DBMOVED; + public static final int READONLY_CANTINIT = CApi.SQLITE_READONLY_CANTINIT; + public static final int READONLY_DIRECTORY = CApi.SQLITE_READONLY_DIRECTORY; + public static final int ABORT_ROLLBACK = CApi.SQLITE_ABORT_ROLLBACK; + public static final int CONSTRAINT_CHECK = CApi.SQLITE_CONSTRAINT_CHECK; + public static final int CONSTRAINT_COMMITHOOK = CApi.SQLITE_CONSTRAINT_COMMITHOOK; + public static final int CONSTRAINT_FOREIGNKEY = CApi.SQLITE_CONSTRAINT_FOREIGNKEY; + public static final int CONSTRAINT_FUNCTION = CApi.SQLITE_CONSTRAINT_FUNCTION; + public static final int CONSTRAINT_NOTNULL = CApi.SQLITE_CONSTRAINT_NOTNULL; + public static final int CONSTRAINT_PRIMARYKEY = CApi.SQLITE_CONSTRAINT_PRIMARYKEY; + public static final int CONSTRAINT_TRIGGER = CApi.SQLITE_CONSTRAINT_TRIGGER; + public static final int CONSTRAINT_UNIQUE = CApi.SQLITE_CONSTRAINT_UNIQUE; + public static final int CONSTRAINT_VTAB = CApi.SQLITE_CONSTRAINT_VTAB; + public static final int CONSTRAINT_ROWID = CApi.SQLITE_CONSTRAINT_ROWID; + public static final int CONSTRAINT_PINNED = CApi.SQLITE_CONSTRAINT_PINNED; + public static final int CONSTRAINT_DATATYPE = CApi.SQLITE_CONSTRAINT_DATATYPE; + public static final int NOTICE_RECOVER_WAL = CApi.SQLITE_NOTICE_RECOVER_WAL; + public static final int NOTICE_RECOVER_ROLLBACK = CApi.SQLITE_NOTICE_RECOVER_ROLLBACK; + public static final int WARNING_AUTOINDEX = CApi.SQLITE_WARNING_AUTOINDEX; + public static final int AUTH_USER = CApi.SQLITE_AUTH_USER; + public static final int OK_LOAD_PERMANENTLY = CApi.SQLITE_OK_LOAD_PERMANENTLY; + public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE; public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE; public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE; @@ -108,10 +213,6 @@ public final class Sqlite implements AutoCloseable { /* We elide the UTF16_ALIGNED from this interface because it is irrelevant for the Java interface. */ - public static final int DONE = CApi.SQLITE_DONE; - public static final int BUSY = CApi.SQLITE_BUSY; - public static final int LOCKED = CApi.SQLITE_LOCKED; - public static final int DENY = CApi.SQLITE_DENY; public static final int IGNORE = CApi.SQLITE_IGNORE; public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX; @@ -1482,4 +1583,34 @@ public final class Sqlite implements AutoCloseable { } CApi.sqlite3_progress_handler( thisDb(), n, phc ); } + + + /** + Callback for use with setAuthorizer(). + */ + public interface Authorizer { + /** + Must function as described for the C-level + sqlite3_set_authorizer() callback. If it throws, the error is + converted to a db-level error and the exception is suppressed. + */ + int call(int opId, String s1, String s2, String s3, String s4); + } + + /** + Analog to sqlite3_set_authorizer(), this sets the current + authorizer callback, or clears if it passed null. + */ + public void setAuthorizer( Authorizer a ) { + org.sqlite.jni.capi.AuthorizerCallback ac = null; + if( null!=a ){ + ac = new org.sqlite.jni.capi.AuthorizerCallback(){ + @Override public int call(int opId, String s1, String s2, String s3, String s4){ + return a.call(opId, s1, s2, s3, s4); + } + }; + } + checkRc( CApi.sqlite3_set_authorizer( thisDb(), ac ) ); + } + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 1af2c8c5d1..b03a83417f 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -888,6 +888,30 @@ public class Tester2 implements Runnable { db.close(); } + private void testAuthorizer(){ + final Sqlite db = openDb(); + final ValueHolder counter = new ValueHolder<>(0); + final ValueHolder authRc = new ValueHolder<>(0); + final Sqlite.Authorizer auth = new Sqlite.Authorizer(){ + public int call(int op, String s0, String s1, String s2, String s3){ + ++counter.value; + //outln("xAuth(): "+s0+" "+s1+" "+s2+" "+s3); + return authRc.value; + } + }; + execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')"); + db.setAuthorizer(auth); + execSql(db, "UPDATE t SET a=1"); + affirm( 1 == counter.value ); + authRc.value = Sqlite.DENY; + int rc = execSql(db, false, "UPDATE t SET a=2"); + affirm( Sqlite.AUTH==rc ); + db.setAuthorizer(null); + rc = execSql(db, false, "UPDATE t SET a=2"); + affirm( 0==rc ); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 82936f69b9..c813cb698b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sprogress-handler\ssupport\sto\sJNI\swrapper1.\sCorrect\sthe\sreturn\stype\sof\sthe\sextended_result_codes()\sJNI\sbinding\sand\sexpose\sit\sto\swrapper1. -D 2023-11-05T01:39:29.450 +C Add\sauthorizer\ssupport\sto\s\sJNI\swrapper1. +D 2023-11-05T01:55:20.977 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -248,7 +248,7 @@ F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7 F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63418129656daa9a9f30e7e7be982bd5ab394b1dbd0 -F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 +F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca F ext/jni/src/org/sqlite/jni/capi/CApi.java a6d4fdd35e4fcfe95c61e343eb389cfaab3d5166e9670730aef14240a982b97b @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 909ebd23111762c878116ebacf73a848c8323fb46e8128eb3d99a85d48905444 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 89d3c4b2ffa9a7d3a125daae66167d29f64058702f65254b7d4a721e3868bd1b F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 923c885609ca9e6793636fc17787d0058c80ce1d7ba5a69eb40e68cc299892d1 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 2397e70955de15f8fb65a7ed421365f018c099d16b8080f81c7553e4dae3d44f F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 822cf3d66beb1efcac1792c8652cbebb80ae998275a33337de46fde1670e0008 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 199b9fb56e06f808d5856494ca8840e9004ff939f27c7c6fda9a60858144f95d F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618 -R dafa52fdba2c999e04b851e5ec6214ab +P 6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88 +R d2d319f241ba72795b6add1f6b68fc9e U stephan -Z 824d9a7ed24ad4091f85bc7e5264c033 +Z a73e3653c86a5ad585af4f9360f1181a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7f82e1d85b..db8f9c9684 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88 \ No newline at end of file +773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0 \ No newline at end of file From 546db3f14a5722ddfdaff671430b32cf84bd8985 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 03:37:33 +0000 Subject: [PATCH 14/55] JNI wrapper1 normalizeSql() now throws UnsupportedOperationException, instead of returning null, if built without SQLITE_ENABLE_NORMALIZE. Remove SQLITE_PREPARE_NORMALIZE from the JNI interface because it's a legacy no-op. FossilOrigin-Name: d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95 --- ext/jni/src/c/sqlite3-jni.h | 2 -- ext/jni/src/org/sqlite/jni/capi/CApi.java | 1 - .../jni/capi/PreupdateHookCallback.java | 3 ++- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 2 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 23 ++++++++++++++++--- manifest | 20 ++++++++-------- manifest.uuid | 2 +- 7 files changed, 34 insertions(+), 19 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index a1097fe57a..c4ca0559f2 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -427,8 +427,6 @@ extern "C" { #define org_sqlite_jni_capi_CApi_SQLITE_OPEN_EXRESCODE 33554432L #undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT #define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT 1L -#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE -#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE 2L #undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB #define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB 4L #undef org_sqlite_jni_capi_CApi_SQLITE_OK diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index f1d4def500..d1930e1e32 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -2279,7 +2279,6 @@ public final class CApi { // prepare flags public static final int SQLITE_PREPARE_PERSISTENT = 1; - public static final int SQLITE_PREPARE_NORMALIZE = 2; public static final int SQLITE_PREPARE_NO_VTAB = 4; // result codes diff --git a/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java index 99d3fb0351..38f7c5613e 100644 --- a/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java +++ b/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java @@ -19,7 +19,8 @@ package org.sqlite.jni.capi; public interface PreupdateHookCallback extends CallbackProxy { /** Must function as described for the C-level sqlite3_preupdate_hook() - callback. + callback. If it throws, the exception is translated to a + db-level error and the exception is suppressed. */ void call(sqlite3 db, int op, String dbName, String dbTable, long iKey1, long iKey2 ); diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index fb53196d26..5655ac7809 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -327,7 +327,7 @@ public class Tester1 implements Runnable { rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)", - SQLITE_PREPARE_NORMALIZE, outStmt); + 0, outStmt); affirm(0 == rc); stmt = outStmt.get(); affirm(0 != stmt.getNativePointer()); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index cf18277329..abf7f20f06 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -178,7 +178,6 @@ public final class Sqlite implements AutoCloseable { public static final int LIMIT_WORKER_THREADS = CApi.SQLITE_LIMIT_WORKER_THREADS; public static final int PREPARE_PERSISTENT = CApi.SQLITE_PREPARE_PERSISTENT; - public static final int PREPARE_NORMALIZE = CApi.SQLITE_PREPARE_NORMALIZE; public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB; public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT; @@ -336,6 +335,22 @@ public final class Sqlite implements AutoCloseable { return CApi.sqlite3_compileoption_used(optName); } + private static boolean hasNormalizeSql = + compileOptionUsed("ENABLE_NORMALIZE"); + + /** + Throws UnsupportedOperationException if check is false. + flag is expected to be the name of an SQLITE_ENABLE_... + build flag. + */ + private static void checkSupported(boolean check, String flag){ + if( !check ){ + throw new UnsupportedOperationException( + "Library was built without "+flag + ); + } + } + /** Analog to sqlite3_complete(). */ @@ -972,10 +987,12 @@ public final class Sqlite implements AutoCloseable { } /** - Analog to sqlite3_normalized_sql(), returning null if the - library is built without the SQLITE_ENABLE_NORMALIZE flag. + Analog to sqlite3_normalized_sql(), but throws + UnsupportedOperationException if the library was built without + the SQLITE_ENABLE_NORMALIZE flag. */ public String normalizedSql(){ + Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_NORMALIZE"); return CApi.sqlite3_normalized_sql(thisStmt()); } diff --git a/manifest b/manifest index c813cb698b..5467b57897 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sauthorizer\ssupport\sto\s\sJNI\swrapper1. -D 2023-11-05T01:55:20.977 +C JNI\swrapper1\snormalizeSql()\snow\sthrows\sUnsupportedOperationException,\sinstead\sof\sreturning\snull,\sif\sbuilt\swithout\sSQLITE_ENABLE_NORMALIZE.\sRemove\sSQLITE_PREPARE_NORMALIZE\sfrom\sthe\sJNI\sinterface\sbecause\sit's\sa\slegacy\sno-op. +D 2023-11-05T03:37:33.975 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -242,7 +242,7 @@ F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c b98d822a35ef4438023c3c14816b5ac17bdbd23bc838ff80b6463c3146a75d14 -F ext/jni/src/c/sqlite3-jni.h 03f66d3b43359dacd7c2c9407d78274dbdb027bc7610985011bf2b462222414e +F ext/jni/src/c/sqlite3-jni.h 9300900f7ec91fffa01445e1ad5815e35a7bece4c9ca07de464641f77195404a F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java a6d4fdd35e4fcfe95c61e343eb389cfaab3d5166e9670730aef14240a982b97b +F ext/jni/src/org/sqlite/jni/capi/CApi.java 41da9b46718b258ad2f195f3dec7265747eff37b6b350b8c427ee290eed0d83c F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -261,7 +261,7 @@ F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbee F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61 F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 68f60aec7aeb5cd4e5fb83449037f668c63cb99f682ee1036cc226d0cbd909b9 F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java aca8f9fa72e3b6602bc9a7dd3ae9f5b2808103fbbee9b2749dc96c19cdc261a1 -F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java 819d938e26208adde17ca4b7ddde1d8cd6915b6ab7b708249a9787beca6bd6b6 +F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java efcf57545c5e282d1dd332fa63329b3b218d98f356ef107a9dbe3979be82213a F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f F ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java e172210a2080e851ebb694c70e9f0bf89284237795e38710a7f5f1b61e3f6787 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 89d3c4b2ffa9a7d3a125daae66167d29f64058702f65254b7d4a721e3868bd1b +F ext/jni/src/org/sqlite/jni/capi/Tester1.java f931370e0beb121390c31747a019690a7cf0927120396862d2a02f75a66bf89c F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,7 +296,7 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 2397e70955de15f8fb65a7ed421365f018c099d16b8080f81c7553e4dae3d44f +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java fbdb8d6643ac1f32c4ffdb76a2ee4580edd0b1935d8d13ad7f581a702635313b F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 199b9fb56e06f808d5856494ca8840e9004ff939f27c7c6fda9a60858144f95d F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af @@ -2142,8 +2142,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 6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88 -R d2d319f241ba72795b6add1f6b68fc9e +P 773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0 +R ea6cc7dea8e7673dad2d1e0c776c92af U stephan -Z a73e3653c86a5ad585af4f9360f1181a +Z d4fc1a1c9c9dbb69dd1ef9b20d8e37f3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index db8f9c9684..624838ac87 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0 \ No newline at end of file +d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95 \ No newline at end of file From ed99e7493aa4f3dd2c49859ca8aaa2c9a831de7a Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 5 Nov 2023 04:20:04 +0000 Subject: [PATCH 15/55] Add incremental blob I/O support to JNI wrapper1. FossilOrigin-Name: 7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0 --- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 2 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 75 ++++++++++++++++++- .../src/org/sqlite/jni/wrapper1/Tester2.java | 26 +++++++ manifest | 16 ++-- manifest.uuid | 2 +- 5 files changed, 110 insertions(+), 11 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 5655ac7809..b25d077408 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1633,7 +1633,7 @@ public class Tester1 implements Runnable { sqlite3_finalize(stmt); b = sqlite3_blob_open(db, "main", "t", "a", - sqlite3_last_insert_rowid(db), 1); + sqlite3_last_insert_rowid(db), 0); affirm( null!=b ); rc = sqlite3_blob_reopen(b, 2); affirm( 0==rc ); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index abf7f20f06..93c294f5de 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -17,6 +17,7 @@ import org.sqlite.jni.capi.CApi; import org.sqlite.jni.capi.sqlite3; import org.sqlite.jni.capi.sqlite3_stmt; import org.sqlite.jni.capi.sqlite3_backup; +import org.sqlite.jni.capi.sqlite3_blob; import org.sqlite.jni.capi.OutputPointer; /** @@ -473,7 +474,7 @@ public final class Sqlite implements AutoCloseable { if( 0!=rc ){ if( CApi.SQLITE_NOMEM==rc ){ throw new OutOfMemoryError(); - }else if( null==db || 0==CApi.sqlite3_errcode(db)){ + }else if( null==db || 0==CApi.sqlite3_errcode(db) ){ throw new SqliteException(rc); }else{ throw new SqliteException(db); @@ -1630,4 +1631,76 @@ public final class Sqlite implements AutoCloseable { checkRc( CApi.sqlite3_set_authorizer( thisDb(), ac ) ); } + /** + Object type for use with blobOpen() + */ + public final class Blob implements AutoCloseable { + private Sqlite db; + private sqlite3_blob b; + Blob(Sqlite db, sqlite3_blob b){ + this.db = db; + this.b = b; + } + + /** + Analog to sqlite3_blob_close(). + */ + @Override public void close(){ + if( null!=b ){ + CApi.sqlite3_blob_close(b); + b = null; + db = null; + } + } + + /** + Analog to sqlite3_blob_reopen() but throws on error. + */ + public void reopen(long newRowId){ + db.checkRc( CApi.sqlite3_blob_reopen(b, newRowId) ); + } + + /** + Analog to sqlite3_blob_write() but throws on error. + */ + public void write( byte[] bytes, int atOffset ){ + db.checkRc( CApi.sqlite3_blob_write(b, bytes, atOffset) ); + } + + /** + Analog to sqlite3_blob_read() but throws on error. + */ + public void read( byte[] dest, int atOffset ){ + db.checkRc( CApi.sqlite3_blob_read(b, dest, atOffset) ); + } + + /** + Analog to sqlite3_blob_bytes(). + */ + public int bytes(){ + return CApi.sqlite3_blob_bytes(b); + } + } + + /** + Analog to sqlite3_blob_open(). Returns a Blob object for the + given database, table, column, and rowid. The blob is opened for + read-write mode if writeable is true, else it is read-only. + + The returned object must eventually be freed, before this + database is closed, by either arranging for it to be auto-closed + or calling its close() method. + + Throws on error. + */ + public Blob blobOpen(String dbName, String tableName, String columnName, + long iRow, boolean writeable){ + final OutputPointer.sqlite3_blob out = new OutputPointer.sqlite3_blob(); + checkRc( + CApi.sqlite3_blob_open(thisDb(), dbName, tableName, columnName, + iRow, writeable ? 1 : 0, out) + ); + return new Blob(this, out.take()); + } + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index b03a83417f..3f7593c709 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -912,6 +912,32 @@ public class Tester2 implements Runnable { db.close(); } + private void testBlobOpen(){ + final Sqlite db = openDb(); + + execSql(db, "CREATE TABLE T(a BLOB);" + +"INSERT INTO t(rowid,a) VALUES(1, 'def'),(2, 'XYZ');" + ); + Sqlite.Blob b = db.blobOpen("main", "t", "a", + db.lastInsertRowId(), true); + affirm( 3==b.bytes() ); + b.write(new byte[] {100, 101, 102 /*"DEF"*/}, 0); + b.close(); + Sqlite.Stmt stmt = db.prepare("SELECT length(a), a FROM t ORDER BY a"); + affirm( stmt.step() ); + affirm( 3 == stmt.columnInt(0) ); + affirm( "def".equals(stmt.columnText16(1)) ); + stmt.finalizeStmt(); + + b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), false); + b.reopen(2); + final byte[] tgt = new byte[3]; + b.read( tgt, 0 ); + affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" ); + b.close(); + db.close(); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 5467b57897..f81c5b0edc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JNI\swrapper1\snormalizeSql()\snow\sthrows\sUnsupportedOperationException,\sinstead\sof\sreturning\snull,\sif\sbuilt\swithout\sSQLITE_ENABLE_NORMALIZE.\sRemove\sSQLITE_PREPARE_NORMALIZE\sfrom\sthe\sJNI\sinterface\sbecause\sit's\sa\slegacy\sno-op. -D 2023-11-05T03:37:33.975 +C Add\sincremental\sblob\sI/O\ssupport\sto\sJNI\swrapper1. +D 2023-11-05T04:20:04.320 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java f931370e0beb121390c31747a019690a7cf0927120396862d2a02f75a66bf89c +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 2898e38cf5ee568a93e760fa9b84f448acb58138d0fca18d146e80a1da7c45fc F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java fbdb8d6643ac1f32c4ffdb76a2ee4580edd0b1935d8d13ad7f581a702635313b +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 6a310fe422d0daf79f7841c9b341f64d843ca7e85ef31829530623a81ecd25fa F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 199b9fb56e06f808d5856494ca8840e9004ff939f27c7c6fda9a60858144f95d +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java a944fd0a9047a51a5074bffd707452d80cf06e715ebc78b541480ee98629fb93 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0 -R ea6cc7dea8e7673dad2d1e0c776c92af +P d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95 +R d10239966e7198eb47ba47ac2878d98e U stephan -Z d4fc1a1c9c9dbb69dd1ef9b20d8e37f3 +Z e8e87bde5ba89e299cdcc353d989a2b2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 624838ac87..63c307a8c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95 \ No newline at end of file +7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0 \ No newline at end of file From a3e8822c4bc081d5b5094839e8c0a7665c3636e5 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 6 Nov 2023 18:40:25 +0000 Subject: [PATCH 16/55] Fix an fts5 problem where a transaction consisting of (a) a DELETE on rowid X, (b) a prefix query, and (c) an INSERT on rowid X, could corrupt the index. FossilOrigin-Name: c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25 --- ext/fts5/fts5_hash.c | 6 ++---- ext/fts5/fts5_index.c | 10 +++++++++- ext/fts5/test/fts5prefix2.test | 30 ++++++++++++++++++++++++++++++ manifest | 18 +++++++++--------- manifest.uuid | 2 +- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/ext/fts5/fts5_hash.c b/ext/fts5/fts5_hash.c index 7e50c36608..391791c7ac 100644 --- a/ext/fts5/fts5_hash.c +++ b/ext/fts5/fts5_hash.c @@ -432,10 +432,8 @@ static Fts5HashEntry *fts5HashEntryMerge( } /* -** Extract all tokens from hash table iHash and link them into a list -** in sorted order. The hash table is cleared before returning. It is -** the responsibility of the caller to free the elements of the returned -** list. +** Link all tokens from hash table iHash into a list in sorted order. The +** tokens are not removed from the hash table. */ static int fts5HashEntrySort( Fts5Hash *pHash, diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 4e6afb2815..c7c02cf6fe 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -2719,6 +2719,14 @@ static void fts5SegIterHashInit( pLeaf->p = (u8*)pList; } } + + /* The call to sqlite3Fts5HashScanInit() causes the hash table to + ** fill the size field of all existing position lists. This means they + ** can no longer be appended to. Since the only scenario in which they + ** can be appended to is if the previous operation on this table was + ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this + ** possibility altogether. */ + p->bDelete = 0; }else{ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), (const char*)pTerm, nTerm, (void**)&pLeaf, &nList @@ -6204,7 +6212,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ /* Flush the hash table to disk if required */ if( iRowidiWriteRowid || (iRowid==p->iWriteRowid && p->bDelete==0) - || (p->nPendingData > p->pConfig->nHashSize) + || (p->nPendingData > p->pConfig->nHashSize) ){ fts5IndexFlush(p); } diff --git a/ext/fts5/test/fts5prefix2.test b/ext/fts5/test/fts5prefix2.test index bf16e81a73..29744c86bf 100644 --- a/ext/fts5/test/fts5prefix2.test +++ b/ext/fts5/test/fts5prefix2.test @@ -52,6 +52,36 @@ do_execsql_test 2.1 { SELECT * FROM t2('to*'); } {top to tommy} +#------------------------------------------------------------------------- + +foreach {tn newrowid} { + 1 122 + 2 123 + 3 124 +} { + reset_db + do_execsql_test 3.$tn.0 { + CREATE VIRTUAL TABLE t12 USING fts5(x); + INSERT INTO t12(rowid, x) VALUES(123, 'wwww'); + } + do_execsql_test 3.$tn.1 { + BEGIN; + DELETE FROM t12 WHERE rowid=123; + SELECT * FROM t12('wwww*'); + INSERT INTO t12(rowid, x) VALUES($newrowid, 'wwww'); + SELECT * FROM t12('wwww*'); + END; + } {wwww} + do_execsql_test 3.$tn.2 { + INSERT INTO t12(t12) VALUES('integrity-check'); + } + do_execsql_test 3.$tn.3 { + SELECT rowid FROM t12('wwww*'); + } $newrowid +} + +finish_test + finish_test diff --git a/manifest b/manifest index f81c5b0edc..23292f0087 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sincremental\sblob\sI/O\ssupport\sto\sJNI\swrapper1. -D 2023-11-05T04:20:04.320 +C Fix\san\sfts5\sproblem\swhere\sa\stransaction\sconsisting\sof\s(a)\sa\sDELETE\son\srowid\sX,\s(b)\sa\sprefix\squery,\sand\s(c)\san\sINSERT\son\srowid\sX,\scould\scorrupt\sthe\sindex. +D 2023-11-06T18:40:25.654 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -93,8 +93,8 @@ F ext/fts5/fts5_aux.c ee770eec0af8646db9e18fc01a0dad7345b5f5e8cbba236704cfae2d77 F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5 F ext/fts5/fts5_config.c 054359543566cbff1ba65a188330660a5457299513ac71c53b3a07d934c7b081 F ext/fts5/fts5_expr.c bd3b81ce669c4104e34ffe66570af1999a317b142c15fccb112de9fb0caa57a6 -F ext/fts5/fts5_hash.c 65e7707bc8774706574346d18c20218facf87de3599b995963c3e6d6809f203d -F ext/fts5/fts5_index.c 730c9c32ada18ce1eb7ff847b36507f4b005d88d47af7b47db521e695a8ea4c7 +F ext/fts5/fts5_hash.c 076058f93327051952a752dc765df1acfe783eb11b419b30652aa1fc1f987902 +F ext/fts5/fts5_index.c 01b671fedd2189f6969385d96facc4c06d9c441f0f91d584386a62b724282f9f F ext/fts5/fts5_main.c a07ed863b8bd9e6fefb62db2fd40a3518eb30a5f7dcfda5be915dd2db45efa2f F ext/fts5/fts5_storage.c 5d10b9bdcce5b90656cad13c7d12ad4148677d4b9e3fca0481fca56d6601426d F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae @@ -193,7 +193,7 @@ F ext/fts5/test/fts5plan.test b65cfcca9ddd6fdaa118c61e17aeec8e8433bc5b6bb307abd1 F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15 F ext/fts5/test/fts5porter2.test 0d251a673f02fa13ca7f011654873b3add20745f7402f108600a23e52d8c7457 F ext/fts5/test/fts5prefix.test a0fa67b06650f2deaa7bf27745899d94e0fb547ad9ecbd08bfad98c04912c056 -F ext/fts5/test/fts5prefix2.test 3847ce46f70b82d61c6095103a9d7c53f2952c40a4704157bc079c04d9c8b18b +F ext/fts5/test/fts5prefix2.test ad751d4a5b029726ee908a7664e27d27bde7584218b8d7944c2a323afd381432 F ext/fts5/test/fts5query.test ac363b17a442620bb0780e93c24f16a5f963dfe2f23dc85647b869efcfada728 F ext/fts5/test/fts5rank.test 30f29e278cd7fb8831ba4f082feb74d8eb90c463bf07113ae200afc2b467ef32 F ext/fts5/test/fts5rebuild.test 55d6f17715cddbf825680dd6551efbc72ed916d8cf1cde40a46fc5d785b451e7 @@ -2142,8 +2142,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 d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95 -R d10239966e7198eb47ba47ac2878d98e -U stephan -Z e8e87bde5ba89e299cdcc353d989a2b2 +P 7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0 +R cd264cc39082738dd835b35e1796876f +U dan +Z ddf602c5afe5ca1e5ab19c1df349a6bc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 63c307a8c4..357f6f02e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0 \ No newline at end of file +c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25 \ No newline at end of file From 23056b608e2c5d7ad2fac621d358294aeb1896d0 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 6 Nov 2023 21:57:15 +0000 Subject: [PATCH 17/55] Add -DSQLITE_ENABLE_COLUMN_METADATA to the JNI build, as per [forum:9205518c0568fdf0|forum post 9205518c0568fdf0]. Add tests for the functions that flag enables so that the build will fail if that flag is missing. FossilOrigin-Name: 7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a --- ext/jni/GNUmakefile | 3 ++- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 4 ++++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index 155e4e7f63..61c816194f 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -227,7 +227,8 @@ SQLITE_OPT += -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_OFFSET_SQL_FUNC \ -DSQLITE_ENABLE_PREUPDATE_HOOK \ -DSQLITE_ENABLE_NORMALIZE \ - -DSQLITE_ENABLE_SQLLOG + -DSQLITE_ENABLE_SQLLOG \ + -DSQLITE_ENABLE_COLUMN_METADATA endif ifeq (1,$(opt.debug)) diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index b25d077408..da9abb53c0 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -382,6 +382,10 @@ public class Tester1 implements Runnable { stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;"); affirm( sqlite3_stmt_readonly(stmt) ); affirm( !sqlite3_stmt_busy(stmt) ); + affirm("t".equals(CApi.sqlite3_column_table_name(stmt,0))); + affirm("main".equals(CApi.sqlite3_column_database_name(stmt,0))); + affirm("a".equals(CApi.sqlite3_column_origin_name(stmt,0))); + int total2 = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ affirm( sqlite3_stmt_busy(stmt) ); diff --git a/manifest b/manifest index 23292f0087..2b0d48205d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sfts5\sproblem\swhere\sa\stransaction\sconsisting\sof\s(a)\sa\sDELETE\son\srowid\sX,\s(b)\sa\sprefix\squery,\sand\s(c)\san\sINSERT\son\srowid\sX,\scould\scorrupt\sthe\sindex. -D 2023-11-06T18:40:25.654 +C Add\s-DSQLITE_ENABLE_COLUMN_METADATA\sto\sthe\sJNI\sbuild,\sas\sper\s[forum:9205518c0568fdf0|forum\spost\s9205518c0568fdf0].\sAdd\stests\sfor\sthe\sfunctions\sthat\sflag\senables\sso\sthat\sthe\sbuild\swill\sfail\sif\sthat\sflag\sis\smissing. +D 2023-11-06T21:57:15.302 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -238,7 +238,7 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 -F ext/jni/GNUmakefile 36919b7c4fb8447da4330df9996c7b064b766957f8b7be214a30eab55a8b8072 +F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c b98d822a35ef4438023c3c14816b5ac17bdbd23bc838ff80b6463c3146a75d14 @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 2898e38cf5ee568a93e760fa9b84f448acb58138d0fca18d146e80a1da7c45fc +F ext/jni/src/org/sqlite/jni/capi/Tester1.java ea18a69a16cf60905a1c24f17a0ffe319fa397d009d444135d0809ada1ad448d F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -2142,8 +2142,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 7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0 -R cd264cc39082738dd835b35e1796876f -U dan -Z ddf602c5afe5ca1e5ab19c1df349a6bc +P c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25 +R a4e5f3d143d3dc87daaa4c71693d0a48 +U stephan +Z 38612cb49abf001f794e1c11b793254d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 357f6f02e0..3fe5e1fd42 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25 \ No newline at end of file +7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a \ No newline at end of file From 6ca0cfd87aad53309c3d376adb5d90b0819d23ab Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 7 Nov 2023 13:22:49 +0000 Subject: [PATCH 18/55] Flesh out [7a63b5b65a79] to be able to build JNI with or without SQLITE_ENABLE_COLUMN_METADATA. FossilOrigin-Name: fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901 --- ext/jni/src/c/sqlite3-jni.c | 2 ++ ext/jni/src/org/sqlite/jni/capi/CApi.java | 15 ++++++++++++--- ext/jni/src/org/sqlite/jni/capi/Tester1.java | 11 ++++++++--- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index c530651cd7..a5cc7e38d5 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -2115,9 +2115,11 @@ WRAP_INT_STMT_INT(1column_1bytes16, sqlite3_column_bytes16) WRAP_INT_STMT(1column_1count, sqlite3_column_count) WRAP_STR_STMT_INT(1column_1decltype, sqlite3_column_decltype) WRAP_STR_STMT_INT(1column_1name, sqlite3_column_name) +#ifdef SQLITE_ENABLE_COLUMN_METADATA WRAP_STR_STMT_INT(1column_1database_1name, sqlite3_column_database_name) WRAP_STR_STMT_INT(1column_1origin_1name, sqlite3_column_origin_name) WRAP_STR_STMT_INT(1column_1table_1name, sqlite3_column_table_name) +#endif WRAP_INT_STMT_INT(1column_1type, sqlite3_column_type) WRAP_INT_STMT(1data_1count, sqlite3_data_count) WRAP_STR_DB_INT(1db_1name, sqlite3_db_name) diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index d1930e1e32..4864b24296 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -622,20 +622,29 @@ public final class CApi { return sqlite3_column_name(stmt.getNativePointer(), ndx); } - static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx); + private static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx); + /** + Only available if built with SQLITE_ENABLE_COLUMN_METADATA. + */ public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_database_name(stmt.getNativePointer(), ndx); } - static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx); + private static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx); + /** + Only available if built with SQLITE_ENABLE_COLUMN_METADATA. + */ public static String sqlite3_column_origin_name(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_origin_name(stmt.getNativePointer(), ndx); } - static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx); + private static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx); + /** + Only available if built with SQLITE_ENABLE_COLUMN_METADATA. + */ public static String sqlite3_column_table_name(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_table_name(stmt.getNativePointer(), ndx); } diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index da9abb53c0..f11a644a3b 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -382,9 +382,14 @@ public class Tester1 implements Runnable { stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;"); affirm( sqlite3_stmt_readonly(stmt) ); affirm( !sqlite3_stmt_busy(stmt) ); - affirm("t".equals(CApi.sqlite3_column_table_name(stmt,0))); - affirm("main".equals(CApi.sqlite3_column_database_name(stmt,0))); - affirm("a".equals(CApi.sqlite3_column_origin_name(stmt,0))); + if( sqlite3_compileoption_used("ENABLE_COLUMN_METADATA") ){ + /* Unlike in native C code, JNI won't trigger an + UnsatisfiedLinkError until these are called (on Linux, at + least). */ + affirm("t".equals(sqlite3_column_table_name(stmt,0))); + affirm("main".equals(sqlite3_column_database_name(stmt,0))); + affirm("a".equals(sqlite3_column_origin_name(stmt,0))); + } int total2 = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ diff --git a/manifest b/manifest index 2b0d48205d..e1f54ab601 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\s-DSQLITE_ENABLE_COLUMN_METADATA\sto\sthe\sJNI\sbuild,\sas\sper\s[forum:9205518c0568fdf0|forum\spost\s9205518c0568fdf0].\sAdd\stests\sfor\sthe\sfunctions\sthat\sflag\senables\sso\sthat\sthe\sbuild\swill\sfail\sif\sthat\sflag\sis\smissing. -D 2023-11-06T21:57:15.302 +C Flesh\sout\s[7a63b5b65a79]\sto\sbe\sable\sto\sbuild\sJNI\swith\sor\swithout\sSQLITE_ENABLE_COLUMN_METADATA. +D 2023-11-07T13:22:49.498 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c b98d822a35ef4438023c3c14816b5ac17bdbd23bc838ff80b6463c3146a75d14 +F ext/jni/src/c/sqlite3-jni.c ac7aa8ef250be4bebf99aa5b610d4a1b5f26578328a458a53db3b075271417ed F ext/jni/src/c/sqlite3-jni.h 9300900f7ec91fffa01445e1ad5815e35a7bece4c9ca07de464641f77195404a F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 41da9b46718b258ad2f195f3dec7265747eff37b6b350b8c427ee290eed0d83c +F ext/jni/src/org/sqlite/jni/capi/CApi.java 75b92b98ee1e621e71466e4bdb3bdff580da688e9873524adffd97db12675eb1 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java ea18a69a16cf60905a1c24f17a0ffe319fa397d009d444135d0809ada1ad448d +F ext/jni/src/org/sqlite/jni/capi/Tester1.java bcfc48cba038e8dc6e08cb9b8a974241e5d9920ab4015c3abf482b7130ac9ba4 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -2142,8 +2142,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 c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25 -R a4e5f3d143d3dc87daaa4c71693d0a48 +P 7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a +R efbde6eb422be28e0f5c5e7a6eec616d U stephan -Z 38612cb49abf001f794e1c11b793254d +Z adceda1b2796226e98fdf1b3f6f9cd13 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3fe5e1fd42..26896fc11a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a \ No newline at end of file +fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901 \ No newline at end of file From 6dc368e632d2c49e4db77f329e55663870995d21 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 7 Nov 2023 13:44:29 +0000 Subject: [PATCH 19/55] Diverse minor cleanups in the JNI pieces. FossilOrigin-Name: 35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4 --- ext/jni/src/c/sqlite3-jni.c | 124 ++++++------- ext/jni/src/org/sqlite/jni/capi/CApi.java | 170 +++++++++--------- ext/jni/src/org/sqlite/jni/capi/sqlite3.java | 2 +- .../src/org/sqlite/jni/capi/sqlite3_stmt.java | 2 +- manifest | 18 +- manifest.uuid | 2 +- 6 files changed, 155 insertions(+), 163 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index a5cc7e38d5..852b0ccceb 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -1474,7 +1474,7 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph, #define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ) #define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ) /* -** S3JniLongPtr_T(X,Y) expects X to be an unqualified sqlite3 struct +** LongPtrGet_T(X,Y) expects X to be an unqualified sqlite3 struct ** type name and Y to be a native pointer to such an object in the ** form of a jlong value. The jlong is simply cast to (X*). This ** approach is, as of 2023-09-27, supplanting the former approach. We @@ -1483,12 +1483,12 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph, ** intptr_t part here is necessary for compatibility with (at least) ** ARM32. */ -#define S3JniLongPtr_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr)) -#define S3JniLongPtr_sqlite3(JLongAsPtr) S3JniLongPtr_T(sqlite3,JLongAsPtr) -#define S3JniLongPtr_sqlite3_backup(JLongAsPtr) S3JniLongPtr_T(sqlite3_backup,JLongAsPtr) -#define S3JniLongPtr_sqlite3_blob(JLongAsPtr) S3JniLongPtr_T(sqlite3_blob,JLongAsPtr) -#define S3JniLongPtr_sqlite3_stmt(JLongAsPtr) S3JniLongPtr_T(sqlite3_stmt,JLongAsPtr) -#define S3JniLongPtr_sqlite3_value(JLongAsPtr) S3JniLongPtr_T(sqlite3_value,JLongAsPtr) +#define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr)) +#define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,JLongAsPtr) +#define LongPtrGet_sqlite3_backup(JLongAsPtr) LongPtrGet_T(sqlite3_backup,JLongAsPtr) +#define LongPtrGet_sqlite3_blob(JLongAsPtr) LongPtrGet_T(sqlite3_blob,JLongAsPtr) +#define LongPtrGet_sqlite3_stmt(JLongAsPtr) LongPtrGet_T(sqlite3_stmt,JLongAsPtr) +#define LongPtrGet_sqlite3_value(JLongAsPtr) LongPtrGet_T(sqlite3_value,JLongAsPtr) /* ** Extracts the new S3JniDb instance from the free-list, or allocates ** one if needed, associates it with pDb, and returns. Returns NULL @@ -1547,7 +1547,7 @@ static void S3JniDb_xDestroy(void *p){ #define S3JniDb_from_c(sqlite3Ptr) \ ((sqlite3Ptr) ? S3JniDb_from_clientdata(sqlite3Ptr) : 0) #define S3JniDb_from_jlong(sqlite3PtrAsLong) \ - S3JniDb_from_c(S3JniLongPtr_T(sqlite3,sqlite3PtrAsLong)) + S3JniDb_from_c(LongPtrGet_T(sqlite3,sqlite3PtrAsLong)) /* ** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out @@ -2052,12 +2052,12 @@ static void udf_xInverse(sqlite3_context* cx, int argc, /** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*)). */ #define WRAP_INT_STMT(JniNameSuffix,CName) \ JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt){ \ - return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt)); \ + return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt)); \ } /** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*,int)). */ #define WRAP_INT_STMT_INT(JniNameSuffix,CName) \ JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint n){ \ - return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)n); \ + return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)n); \ } /** Create a trivial JNI wrapper for (boolean CName(sqlite3_stmt*)). */ #define WRAP_BOOL_STMT(JniNameSuffix,CName) \ @@ -2068,41 +2068,41 @@ static void udf_xInverse(sqlite3_context* cx, int argc, #define WRAP_STR_STMT_INT(JniNameSuffix,CName) \ JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint ndx){ \ return s3jni_utf8_to_jstring( \ - CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx), \ + CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx), \ -1); \ } /** Create a trivial JNI wrapper for (boolean CName(sqlite3*)). */ #define WRAP_BOOL_DB(JniNameSuffix,CName) \ JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \ - return CName(S3JniLongPtr_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \ + return CName(LongPtrGet_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \ } /** Create a trivial JNI wrapper for (int CName(sqlite3*)). */ #define WRAP_INT_DB(JniNameSuffix,CName) \ JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \ - return (jint)CName(S3JniLongPtr_sqlite3(jpDb)); \ + return (jint)CName(LongPtrGet_sqlite3(jpDb)); \ } /** Create a trivial JNI wrapper for (int64 CName(sqlite3*)). */ #define WRAP_INT64_DB(JniNameSuffix,CName) \ JniDecl(jlong,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \ - return (jlong)CName(S3JniLongPtr_sqlite3(jpDb)); \ + return (jlong)CName(LongPtrGet_sqlite3(jpDb)); \ } /** Create a trivial JNI wrapper for (jstring CName(sqlite3*,int)). */ #define WRAP_STR_DB_INT(JniNameSuffix,CName) \ JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpDb, jint ndx){ \ return s3jni_utf8_to_jstring( \ - CName(S3JniLongPtr_sqlite3(jpDb), (int)ndx), \ + CName(LongPtrGet_sqlite3(jpDb), (int)ndx), \ -1); \ } /** Create a trivial JNI wrapper for (int CName(sqlite3_value*)). */ #define WRAP_INT_SVALUE(JniNameSuffix,CName,DfltOnNull) \ JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \ + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \ return (jint)(sv ? CName(sv): DfltOnNull); \ } /** Create a trivial JNI wrapper for (boolean CName(sqlite3_value*)). */ #define WRAP_BOOL_SVALUE(JniNameSuffix,CName,DfltOnNull) \ JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \ + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \ return (jint)(sv ? CName(sv) : DfltOnNull) \ ? JNI_TRUE : JNI_FALSE; \ } @@ -2317,7 +2317,7 @@ S3JniApi(sqlite3_backup_finish(),jint,1backup_1finish)( ){ int rc = 0; if( jpBack!=0 ){ - rc = sqlite3_backup_finish( S3JniLongPtr_sqlite3_backup(jpBack) ); + rc = sqlite3_backup_finish( LongPtrGet_sqlite3_backup(jpBack) ); } return rc; } @@ -2326,8 +2326,8 @@ S3JniApi(sqlite3_backup_init(),jobject,1backup_1init)( JniArgsEnvClass, jlong jpDbDest, jstring jTDest, jlong jpDbSrc, jstring jTSrc ){ - sqlite3 * const pDest = S3JniLongPtr_sqlite3(jpDbDest); - sqlite3 * const pSrc = S3JniLongPtr_sqlite3(jpDbSrc); + sqlite3 * const pDest = LongPtrGet_sqlite3(jpDbDest); + sqlite3 * const pSrc = LongPtrGet_sqlite3(jpDbSrc); char * const zDest = s3jni_jstring_to_utf8(jTDest, 0); char * const zSrc = s3jni_jstring_to_utf8(jTSrc, 0); jobject rv = 0; @@ -2350,19 +2350,19 @@ S3JniApi(sqlite3_backup_init(),jobject,1backup_1init)( S3JniApi(sqlite3_backup_pagecount(),jint,1backup_1pagecount)( JniArgsEnvClass, jlong jpBack ){ - return sqlite3_backup_pagecount(S3JniLongPtr_sqlite3_backup(jpBack)); + return sqlite3_backup_pagecount(LongPtrGet_sqlite3_backup(jpBack)); } S3JniApi(sqlite3_backup_remaining(),jint,1backup_1remaining)( JniArgsEnvClass, jlong jpBack ){ - return sqlite3_backup_remaining(S3JniLongPtr_sqlite3_backup(jpBack)); + return sqlite3_backup_remaining(LongPtrGet_sqlite3_backup(jpBack)); } S3JniApi(sqlite3_backup_step(),jint,1backup_1step)( JniArgsEnvClass, jlong jpBack, jint nPage ){ - return sqlite3_backup_step(S3JniLongPtr_sqlite3_backup(jpBack), (int)nPage); + return sqlite3_backup_step(LongPtrGet_sqlite3_backup(jpBack), (int)nPage); } S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)( @@ -2375,13 +2375,13 @@ S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)( if( nMax>nBA ){ nMax = nBA; } - rc = sqlite3_bind_blob(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, + rc = sqlite3_bind_blob(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, pBuf, (int)nMax, SQLITE_TRANSIENT); s3jni_jbyteArray_release(baData, pBuf); }else{ rc = baData ? SQLITE_NOMEM - : sqlite3_bind_null( S3JniLongPtr_sqlite3_stmt(jpStmt), ndx ); + : sqlite3_bind_null( LongPtrGet_sqlite3_stmt(jpStmt), ndx ); } return (jint)rc; } @@ -2389,20 +2389,20 @@ S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)( S3JniApi(sqlite3_bind_double(),jint,1bind_1double)( JniArgsEnvClass, jlong jpStmt, jint ndx, jdouble val ){ - return (jint)sqlite3_bind_double(S3JniLongPtr_sqlite3_stmt(jpStmt), + return (jint)sqlite3_bind_double(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (double)val); } S3JniApi(sqlite3_bind_int(),jint,1bind_1int)( JniArgsEnvClass, jlong jpStmt, jint ndx, jint val ){ - return (jint)sqlite3_bind_int(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (int)val); + return (jint)sqlite3_bind_int(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)val); } S3JniApi(sqlite3_bind_int64(),jint,1bind_1int64)( JniArgsEnvClass, jlong jpStmt, jint ndx, jlong val ){ - return (jint)sqlite3_bind_int64(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val); + return (jint)sqlite3_bind_int64(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val); } /* @@ -2411,7 +2411,7 @@ S3JniApi(sqlite3_bind_int64(),jint,1bind_1int64)( S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)( JniArgsEnvClass, jlong jpStmt, jint ndx, jobject val ){ - sqlite3_stmt * const pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt); + sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt); int rc = SQLITE_MISUSE; if(pStmt){ @@ -2431,13 +2431,13 @@ S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)( S3JniApi(sqlite3_bind_null(),jint,1bind_1null)( JniArgsEnvClass, jlong jpStmt, jint ndx ){ - return (jint)sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx); + return (jint)sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx); } S3JniApi(sqlite3_bind_parameter_count(),jint,1bind_1parameter_1count)( JniArgsEnvClass, jlong jpStmt ){ - return (jint)sqlite3_bind_parameter_count(S3JniLongPtr_sqlite3_stmt(jpStmt)); + return (jint)sqlite3_bind_parameter_count(LongPtrGet_sqlite3_stmt(jpStmt)); } S3JniApi(sqlite3_bind_parameter_index(),jint,1bind_1parameter_1index)( @@ -2446,7 +2446,7 @@ S3JniApi(sqlite3_bind_parameter_index(),jint,1bind_1parameter_1index)( int rc = 0; jbyte * const pBuf = s3jni_jbyteArray_bytes(jName); if( pBuf ){ - rc = sqlite3_bind_parameter_index(S3JniLongPtr_sqlite3_stmt(jpStmt), + rc = sqlite3_bind_parameter_index(LongPtrGet_sqlite3_stmt(jpStmt), (const char *)pBuf); s3jni_jbyteArray_release(jName, pBuf); } @@ -2457,7 +2457,7 @@ S3JniApi(sqlite3_bind_parameter_name(),jstring,1bind_1parameter_1name)( JniArgsEnvClass, jlong jpStmt, jint ndx ){ const char *z = - sqlite3_bind_parameter_name(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx); + sqlite3_bind_parameter_name(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx); return z ? s3jni_utf8_to_jstring(z, -1) : 0; } @@ -2479,14 +2479,14 @@ static int s3jni__bind_text(int is16, JNIEnv *env, jlong jpStmt, jint ndx, such cases, we do not expose the byte-limit arguments in the public API. */ rc = is16 - ? sqlite3_bind_text16(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, + ? sqlite3_bind_text16(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, pBuf, (int)nMax, SQLITE_TRANSIENT) - : sqlite3_bind_text(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, + : sqlite3_bind_text(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (const char *)pBuf, (int)nMax, SQLITE_TRANSIENT); }else{ rc = baData - ? sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx) + ? sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx) : SQLITE_NOMEM; } s3jni_jbyteArray_release(baData, pBuf); @@ -2510,9 +2510,9 @@ S3JniApi(sqlite3_bind_value(),jint,1bind_1value)( JniArgsEnvClass, jlong jpStmt, jint ndx, jlong jpValue ){ int rc = 0; - sqlite3_stmt * pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt); + sqlite3_stmt * pStmt = LongPtrGet_sqlite3_stmt(jpStmt); if( pStmt ){ - sqlite3_value *v = S3JniLongPtr_sqlite3_value(jpValue); + sqlite3_value *v = LongPtrGet_sqlite3_value(jpValue); if( v ){ rc = sqlite3_bind_value(pStmt, (int)ndx, v); }else{ @@ -2527,27 +2527,27 @@ S3JniApi(sqlite3_bind_value(),jint,1bind_1value)( S3JniApi(sqlite3_bind_zeroblob(),jint,1bind_1zeroblob)( JniArgsEnvClass, jlong jpStmt, jint ndx, jint n ){ - return (jint)sqlite3_bind_zeroblob(S3JniLongPtr_sqlite3_stmt(jpStmt), + return (jint)sqlite3_bind_zeroblob(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)n); } S3JniApi(sqlite3_bind_zeroblob64(),jint,1bind_1zeroblob64)( JniArgsEnvClass, jlong jpStmt, jint ndx, jlong n ){ - return (jint)sqlite3_bind_zeroblob64(S3JniLongPtr_sqlite3_stmt(jpStmt), + return (jint)sqlite3_bind_zeroblob64(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_uint64)n); } S3JniApi(sqlite3_blob_bytes(),jint,1blob_1bytes)( JniArgsEnvClass, jlong jpBlob ){ - return sqlite3_blob_bytes(S3JniLongPtr_sqlite3_blob(jpBlob)); + return sqlite3_blob_bytes(LongPtrGet_sqlite3_blob(jpBlob)); } S3JniApi(sqlite3_blob_close(),jint,1blob_1close)( JniArgsEnvClass, jlong jpBlob ){ - sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob); + sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob); return b ? (jint)sqlite3_blob_close(b) : SQLITE_MISUSE; } @@ -2555,7 +2555,7 @@ S3JniApi(sqlite3_blob_open(),jint,1blob_1open)( JniArgsEnvClass, jlong jpDb, jstring jDbName, jstring jTbl, jstring jCol, jlong jRowId, jint flags, jobject jOut ){ - sqlite3 * const db = S3JniLongPtr_sqlite3(jpDb); + sqlite3 * const db = LongPtrGet_sqlite3(jpDb); sqlite3_blob * pBlob = 0; char * zDbName = 0, * zTableName = 0, * zColumnName = 0; int rc; @@ -2589,7 +2589,7 @@ S3JniApi(sqlite3_blob_read(),jint,1blob_1read)( int rc = jTgt ? (pBa ? SQLITE_MISUSE : SQLITE_NOMEM) : SQLITE_MISUSE; if( pBa ){ jsize const nTgt = (*env)->GetArrayLength(env, jTgt); - rc = sqlite3_blob_read(S3JniLongPtr_sqlite3_blob(jpBlob), pBa, + rc = sqlite3_blob_read(LongPtrGet_sqlite3_blob(jpBlob), pBa, (int)nTgt, (int)iOffset); if( 0==rc ){ s3jni_jbyteArray_commit(jTgt, pBa); @@ -2603,14 +2603,14 @@ S3JniApi(sqlite3_blob_read(),jint,1blob_1read)( S3JniApi(sqlite3_blob_reopen(),jint,1blob_1reopen)( JniArgsEnvClass, jlong jpBlob, jlong iNewRowId ){ - return (jint)sqlite3_blob_reopen(S3JniLongPtr_sqlite3_blob(jpBlob), + return (jint)sqlite3_blob_reopen(LongPtrGet_sqlite3_blob(jpBlob), (sqlite3_int64)iNewRowId); } S3JniApi(sqlite3_blob_write(),jint,1blob_1write)( JniArgsEnvClass, jlong jpBlob, jbyteArray jBa, jint iOffset ){ - sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob); + sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob); jbyte * const pBuf = b ? s3jni_jbyteArray_bytes(jBa) : 0; const jsize nBA = pBuf ? (*env)->GetArrayLength(env, jBa) : 0; int rc = SQLITE_MISUSE; @@ -2872,7 +2872,7 @@ S3JniApi(sqlite3_column_int64(),jlong,1column_1int64)( S3JniApi(sqlite3_column_java_object(),jobject,1column_1java_1object)( JniArgsEnvClass, jlong jpStmt, jint ndx ){ - sqlite3_stmt * const stmt = S3JniLongPtr_sqlite3_stmt(jpStmt); + sqlite3_stmt * const stmt = LongPtrGet_sqlite3_stmt(jpStmt); jobject rv = 0; if( stmt ){ sqlite3 * const db = sqlite3_db_handle(stmt); @@ -3612,7 +3612,7 @@ S3JniApi(sqlite3_finalize(),jint,1finalize)( JniArgsEnvClass, jlong jpStmt ){ return jpStmt - ? sqlite3_finalize(S3JniLongPtr_sqlite3_stmt(jpStmt)) + ? sqlite3_finalize(LongPtrGet_sqlite3_stmt(jpStmt)) : 0; } @@ -3841,7 +3841,7 @@ jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self, sqlite3_stmt * pStmt = 0; jobject jStmt = 0; const char * zTail = 0; - sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb); + sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb); jbyte * const pBuf = pDb ? s3jni_jbyteArray_bytes(baSql) : 0; int rc = SQLITE_ERROR; @@ -4095,7 +4095,7 @@ S3JniApi(sqlite3_preupdate_hook(),jobject,1preupdate_1hook)( static int s3jni_preupdate_newold(JNIEnv * const env, int isNew, jlong jpDb, jint iCol, jobject jOut){ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK - sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb); + sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb); int rc = SQLITE_MISUSE; if( pDb ){ sqlite3_value * pOut = 0; @@ -4852,7 +4852,7 @@ S3JniApi(sqlite3_update_hook(),jobject,1update_1hook)( S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); const jbyte * pBytes = sv ? sqlite3_value_blob(sv) : 0; int const nLen = pBytes ? sqlite3_value_bytes(sv) : 0; @@ -4865,14 +4865,14 @@ S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)( S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return sv ? sqlite3_value_bytes(sv) : 0; } S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return sv ? sqlite3_value_bytes16(sv) : 0; } @@ -4880,7 +4880,7 @@ S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)( S3JniApi(sqlite3_value_double(),jdouble,1value_1double)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return (jdouble) (sv ? sqlite3_value_double(sv) : 0.0); } @@ -4888,7 +4888,7 @@ S3JniApi(sqlite3_value_double(),jdouble,1value_1double)( S3JniApi(sqlite3_value_dup(),jobject,1value_1dup)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); sqlite3_value * const sd = sv ? sqlite3_value_dup(sv) : 0; jobject rv = sd ? new_java_sqlite3_value(env, sd) : 0; if( sd && !rv ) { @@ -4901,7 +4901,7 @@ S3JniApi(sqlite3_value_dup(),jobject,1value_1dup)( S3JniApi(sqlite3_value_free(),void,1value_1free)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); if( sv ){ sqlite3_value_free(sv); } @@ -4910,21 +4910,21 @@ S3JniApi(sqlite3_value_free(),void,1value_1free)( S3JniApi(sqlite3_value_int(),jint,1value_1int)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return (jint) (sv ? sqlite3_value_int(sv) : 0); } S3JniApi(sqlite3_value_int64(),jlong,1value_1int64)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return (jlong) (sv ? sqlite3_value_int64(sv) : 0LL); } S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return sv ? sqlite3_value_pointer(sv, s3jni__value_jref_key) : 0; @@ -4933,7 +4933,7 @@ S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)( S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0; int const n = p ? sqlite3_value_bytes(sv) : 0; return p ? s3jni_new_jbyteArray(p, n) : 0; @@ -4944,7 +4944,7 @@ S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)( S3JniApi(sqlite3_value_text(),jstring,1value_1text)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0; int const n = p ? sqlite3_value_bytes(sv) : 0; return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0; @@ -4954,7 +4954,7 @@ S3JniApi(sqlite3_value_text(),jstring,1value_1text)( S3JniApi(sqlite3_value_text16(),jstring,1value_1text16)( JniArgsEnvClass, jlong jpSVal ){ - sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); + sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); const int n = sv ? sqlite3_value_bytes16(sv) : 0; const void * const p = sv ? sqlite3_value_text16(sv) : 0; return p ? s3jni_text16_to_jstring(env, p, n) : 0; diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 4864b24296..8bdcb3cf2d 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -164,13 +164,13 @@ public final class CApi { */ public static native int sqlite3_auto_extension(@NotNull AutoExtensionCallback callback); - static native int sqlite3_backup_finish(@NotNull long ptrToBackup); + private static native int sqlite3_backup_finish(@NotNull long ptrToBackup); public static int sqlite3_backup_finish(@NotNull sqlite3_backup b){ - return sqlite3_backup_finish(b.clearNativePointer()); + return null==b ? 0 : sqlite3_backup_finish(b.clearNativePointer()); } - static native sqlite3_backup sqlite3_backup_init( + private static native sqlite3_backup sqlite3_backup_init( @NotNull long ptrToDbDest, @NotNull String destTableName, @NotNull long ptrToDbSrc, @NotNull String srcTableName ); @@ -183,25 +183,25 @@ public final class CApi { dbSrc.getNativePointer(), srcTableName ); } - static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup); + private static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup); public static int sqlite3_backup_pagecount(@NotNull sqlite3_backup b){ return sqlite3_backup_pagecount(b.getNativePointer()); } - static native int sqlite3_backup_remaining(@NotNull long ptrToBackup); + private static native int sqlite3_backup_remaining(@NotNull long ptrToBackup); public static int sqlite3_backup_remaining(@NotNull sqlite3_backup b){ return sqlite3_backup_remaining(b.getNativePointer()); } - static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage); + private static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage); public static int sqlite3_backup_step(@NotNull sqlite3_backup b, int nPage){ return sqlite3_backup_step(b.getNativePointer(), nPage); } - static native int sqlite3_bind_blob( + private static native int sqlite3_bind_blob( @NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int n ); @@ -223,7 +223,7 @@ public final class CApi { : sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, data.length); } - static native int sqlite3_bind_double( + private static native int sqlite3_bind_double( @NotNull long ptrToStmt, int ndx, double v ); @@ -233,7 +233,7 @@ public final class CApi { return sqlite3_bind_double(stmt.getNativePointer(), ndx, v); } - static native int sqlite3_bind_int( + private static native int sqlite3_bind_int( @NotNull long ptrToStmt, int ndx, int v ); @@ -243,7 +243,7 @@ public final class CApi { return sqlite3_bind_int(stmt.getNativePointer(), ndx, v); } - static native int sqlite3_bind_int64( + private static native int sqlite3_bind_int64( @NotNull long ptrToStmt, int ndx, long v ); @@ -251,7 +251,7 @@ public final class CApi { return sqlite3_bind_int64( stmt.getNativePointer(), ndx, v ); } - static native int sqlite3_bind_java_object( + private static native int sqlite3_bind_java_object( @NotNull long ptrToStmt, int ndx, @Nullable Object o ); @@ -267,13 +267,13 @@ public final class CApi { return sqlite3_bind_java_object(stmt.getNativePointer(), ndx, o); } - static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx); + private static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx); public static int sqlite3_bind_null(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_bind_null(stmt.getNativePointer(), ndx); } - static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt); + private static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt); public static int sqlite3_bind_parameter_count(@NotNull sqlite3_stmt stmt){ return sqlite3_bind_parameter_count(stmt.getNativePointer()); @@ -300,7 +300,7 @@ public final class CApi { return null==utf8 ? 0 : sqlite3_bind_parameter_index(stmt.getNativePointer(), utf8); } - static native String sqlite3_bind_parameter_name( + private static native String sqlite3_bind_parameter_name( @NotNull long ptrToStmt, int index ); @@ -308,7 +308,7 @@ public final class CApi { return sqlite3_bind_parameter_name(stmt.getNativePointer(), index); } - static native int sqlite3_bind_text( + private static native int sqlite3_bind_text( @NotNull long ptrToStmt, int ndx, @Nullable byte[] utf8, int maxBytes ); @@ -352,7 +352,7 @@ public final class CApi { : sqlite3_bind_text(stmt.getNativePointer(), ndx, utf8, utf8.length); } - static native int sqlite3_bind_text16( + private static native int sqlite3_bind_text16( @NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int maxBytes ); @@ -393,7 +393,7 @@ public final class CApi { : sqlite3_bind_text16(stmt.getNativePointer(), ndx, data, data.length); } - static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue); + private static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue); /** Functions like the C-level sqlite3_bind_value(), or @@ -404,13 +404,13 @@ public final class CApi { null==val ? 0L : val.getNativePointer()); } - static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n); + private static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n); public static int sqlite3_bind_zeroblob(@NotNull sqlite3_stmt stmt, int ndx, int n){ return sqlite3_bind_zeroblob(stmt.getNativePointer(), ndx, n); } - static native int sqlite3_bind_zeroblob64( + private static native int sqlite3_bind_zeroblob64( @NotNull long ptrToStmt, int ndx, long n ); @@ -418,19 +418,19 @@ public final class CApi { return sqlite3_bind_zeroblob64(stmt.getNativePointer(), ndx, n); } - static native int sqlite3_blob_bytes(@NotNull long ptrToBlob); + private static native int sqlite3_blob_bytes(@NotNull long ptrToBlob); public static int sqlite3_blob_bytes(@NotNull sqlite3_blob blob){ return sqlite3_blob_bytes(blob.getNativePointer()); } - static native int sqlite3_blob_close(@Nullable long ptrToBlob); + private static native int sqlite3_blob_close(@Nullable long ptrToBlob); public static int sqlite3_blob_close(@Nullable sqlite3_blob blob){ - return sqlite3_blob_close(blob.clearNativePointer()); + return null==blob ? 0 : sqlite3_blob_close(blob.clearNativePointer()); } - static native int sqlite3_blob_open( + private static native int sqlite3_blob_open( @NotNull long ptrToDb, @NotNull String dbName, @NotNull String tableName, @NotNull String columnName, long iRow, int flags, @NotNull OutputPointer.sqlite3_blob out @@ -458,7 +458,7 @@ public final class CApi { return out.take(); }; - static native int sqlite3_blob_read( + private static native int sqlite3_blob_read( @NotNull long ptrToBlob, @NotNull byte[] target, int iOffset ); @@ -468,7 +468,7 @@ public final class CApi { return sqlite3_blob_read(b.getNativePointer(), target, iOffset); } - static native int sqlite3_blob_reopen( + private static native int sqlite3_blob_reopen( @NotNull long ptrToBlob, long newRowId ); @@ -476,7 +476,7 @@ public final class CApi { return sqlite3_blob_reopen(b.getNativePointer(), newRowId); } - static native int sqlite3_blob_write( + private static native int sqlite3_blob_write( @NotNull long ptrToBlob, @NotNull byte[] bytes, int iOffset ); @@ -486,7 +486,7 @@ public final class CApi { return sqlite3_blob_write(b.getNativePointer(), bytes, iOffset); } - static native int sqlite3_busy_handler( + private static native int sqlite3_busy_handler( @NotNull long ptrToDb, @Nullable BusyHandlerCallback handler ); @@ -501,7 +501,7 @@ public final class CApi { return sqlite3_busy_handler(db.getNativePointer(), handler); } - static native int sqlite3_busy_timeout(@NotNull long ptrToDb, int ms); + private static native int sqlite3_busy_timeout(@NotNull long ptrToDb, int ms); public static int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms){ return sqlite3_busy_timeout(db.getNativePointer(), ms); @@ -511,64 +511,59 @@ public final class CApi { @NotNull AutoExtensionCallback ax ); - static native int sqlite3_changes(@NotNull long ptrToDb); + private static native int sqlite3_changes(@NotNull long ptrToDb); public static int sqlite3_changes(@NotNull sqlite3 db){ return sqlite3_changes(db.getNativePointer()); } - static native long sqlite3_changes64(@NotNull long ptrToDb); + private static native long sqlite3_changes64(@NotNull long ptrToDb); public static long sqlite3_changes64(@NotNull sqlite3 db){ return sqlite3_changes64(db.getNativePointer()); } - static native int sqlite3_clear_bindings(@NotNull long ptrToStmt); + private static native int sqlite3_clear_bindings(@NotNull long ptrToStmt); public static int sqlite3_clear_bindings(@NotNull sqlite3_stmt stmt){ return sqlite3_clear_bindings(stmt.getNativePointer()); } - static native int sqlite3_close(@Nullable long ptrToDb); + private static native int sqlite3_close(@Nullable long ptrToDb); public static int sqlite3_close(@Nullable sqlite3 db){ - int rc = 0; - if( null!=db ){ - rc = sqlite3_close(db.getNativePointer()); - if( 0==rc ) db.clearNativePointer(); - } - return rc; + return null==db ? 0 : sqlite3_close(db.clearNativePointer()); } - static native int sqlite3_close_v2(@Nullable long ptrToDb); + private static native int sqlite3_close_v2(@Nullable long ptrToDb); public static int sqlite3_close_v2(@Nullable sqlite3 db){ - return db==null ? 0 : sqlite3_close_v2(db.clearNativePointer()); + return null==db ? 0 : sqlite3_close_v2(db.clearNativePointer()); } public static native byte[] sqlite3_column_blob( @NotNull sqlite3_stmt stmt, int ndx ); - static native int sqlite3_column_bytes(@NotNull long ptrToStmt, int ndx); + private static native int sqlite3_column_bytes(@NotNull long ptrToStmt, int ndx); public static int sqlite3_column_bytes(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_bytes(stmt.getNativePointer(), ndx); } - static native int sqlite3_column_bytes16(@NotNull long ptrToStmt, int ndx); + private static native int sqlite3_column_bytes16(@NotNull long ptrToStmt, int ndx); public static int sqlite3_column_bytes16(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_bytes16(stmt.getNativePointer(), ndx); } - static native int sqlite3_column_count(@NotNull long ptrToStmt); + private static native int sqlite3_column_count(@NotNull long ptrToStmt); public static int sqlite3_column_count(@NotNull sqlite3_stmt stmt){ return sqlite3_column_count(stmt.getNativePointer()); } - static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx); + private static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx); public static String sqlite3_column_decltype(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_decltype(stmt.getNativePointer(), ndx); @@ -586,7 +581,7 @@ public final class CApi { @NotNull sqlite3_stmt stmt, int ndx ); - static native Object sqlite3_column_java_object( + private static native Object sqlite3_column_java_object( @NotNull long ptrToStmt, int ndx ); @@ -616,7 +611,7 @@ public final class CApi { return type.isInstance(o) ? (T)o : null; } - static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx); + private static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx); public static String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_name(stmt.getNativePointer(), ndx); @@ -702,7 +697,7 @@ public final class CApi { // return rv; // } - static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx); + private static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx); public static int sqlite3_column_type(@NotNull sqlite3_stmt stmt, int ndx){ return sqlite3_column_type(stmt.getNativePointer(), ndx); @@ -712,7 +707,7 @@ public final class CApi { @NotNull sqlite3_stmt stmt, int ndx ); - static native int sqlite3_collation_needed( + private static native int sqlite3_collation_needed( @NotNull long ptrToDb, @Nullable CollationNeededCallback callback ); @@ -726,7 +721,7 @@ public final class CApi { return sqlite3_collation_needed(db.getNativePointer(), callback); } - static native CommitHookCallback sqlite3_commit_hook( + private static native CommitHookCallback sqlite3_commit_hook( @NotNull long ptrToDb, @Nullable CommitHookCallback hook ); @@ -825,7 +820,7 @@ public final class CApi { int nArg, int eTextRep, @NotNull SQLFunction func ); - static native int sqlite3_data_count(@NotNull long ptrToStmt); + private static native int sqlite3_data_count(@NotNull long ptrToStmt); public static int sqlite3_data_count(@NotNull sqlite3_stmt stmt){ return sqlite3_data_count(stmt.getNativePointer()); @@ -879,7 +874,7 @@ public final class CApi { public static native String sqlite3_errmsg(@NotNull sqlite3 db); - static native int sqlite3_error_offset(@NotNull long ptrToDb); + private static native int sqlite3_error_offset(@NotNull long ptrToDb); /** Note that the returned byte offset values assume UTF-8-encoded @@ -893,7 +888,7 @@ public final class CApi { public static native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt); - static native int sqlite3_extended_errcode(@NotNull long ptrToDb); + private static native int sqlite3_extended_errcode(@NotNull long ptrToDb); public static int sqlite3_extended_errcode(@NotNull sqlite3 db){ return sqlite3_extended_errcode(db.getNativePointer()); @@ -903,7 +898,7 @@ public final class CApi { @NotNull sqlite3 db, boolean on ); - static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb); + private static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb); public static boolean sqlite3_get_autocommit(@NotNull sqlite3 db){ return sqlite3_get_autocommit(db.getNativePointer()); @@ -913,7 +908,7 @@ public final class CApi { @NotNull sqlite3_context cx, int n ); - static native int sqlite3_finalize(long ptrToStmt); + private static native int sqlite3_finalize(long ptrToStmt); public static int sqlite3_finalize(@NotNull sqlite3_stmt stmt){ return null==stmt ? 0 : sqlite3_finalize(stmt.clearNativePointer()); @@ -1285,7 +1280,7 @@ public final class CApi { return sqlite3_prepare_multi(db, sql, 0, p); } - static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb); + private static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb); /** If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this @@ -1296,7 +1291,7 @@ public final class CApi { return sqlite3_preupdate_blobwrite(db.getNativePointer()); } - static native int sqlite3_preupdate_count(@NotNull long ptrToDb); + private static native int sqlite3_preupdate_count(@NotNull long ptrToDb); /** If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this @@ -1307,7 +1302,7 @@ public final class CApi { return sqlite3_preupdate_count(db.getNativePointer()); } - static native int sqlite3_preupdate_depth(@NotNull long ptrToDb); + private static native int sqlite3_preupdate_depth(@NotNull long ptrToDb); /** If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this @@ -1318,7 +1313,7 @@ public final class CApi { return sqlite3_preupdate_depth(db.getNativePointer()); } - static native PreupdateHookCallback sqlite3_preupdate_hook( + private static native PreupdateHookCallback sqlite3_preupdate_hook( @NotNull long ptrToDb, @Nullable PreupdateHookCallback hook ); @@ -1333,7 +1328,7 @@ public final class CApi { return sqlite3_preupdate_hook(db.getNativePointer(), hook); } - static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col, + private static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col, @NotNull OutputPointer.sqlite3_value out); /** @@ -1356,7 +1351,7 @@ public final class CApi { return out.take(); } - static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col, + private static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col, @NotNull OutputPointer.sqlite3_value out); /** @@ -1407,7 +1402,7 @@ public final class CApi { results in the C-level sqlite3_result_error() being called with a complaint about the invalid argument. */ - static native void sqlite3_result_error( + private static native void sqlite3_result_error( @NotNull sqlite3_context cx, @NotNull byte[] msg, int eTextRep ); @@ -1479,9 +1474,6 @@ public final class CApi { cross-language semantic mismatch and (B) Java doesn't need that argument for its intended purpose (type safety). -

Note that there is no sqlite3_column_java_object(), as the - C-level API has no sqlite3_column_pointer() to proxy. - @see #sqlite3_value_java_object @see #sqlite3_bind_java_object */ @@ -1684,7 +1676,7 @@ public final class CApi { } } - static native RollbackHookCallback sqlite3_rollback_hook( + private static native RollbackHookCallback sqlite3_rollback_hook( @NotNull long ptrToDb, @Nullable RollbackHookCallback hook ); @@ -1740,13 +1732,13 @@ public final class CApi { public static native boolean sqlite3_stmt_busy(@NotNull sqlite3_stmt stmt); - static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op); + private static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op); public static int sqlite3_stmt_explain(@NotNull sqlite3_stmt stmt, int op){ return sqlite3_stmt_explain(stmt.getNativePointer(), op); } - static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt); + private static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt); public static int sqlite3_stmt_isexplain(@NotNull sqlite3_stmt stmt){ return sqlite3_stmt_isexplain(stmt.getNativePointer()); @@ -1796,7 +1788,7 @@ public final class CApi { (int)escChar); } - static native int sqlite3_system_errno(@NotNull long ptrToDb); + private static native int sqlite3_system_errno(@NotNull long ptrToDb); public static int sqlite3_system_errno(@NotNull sqlite3 db){ return sqlite3_system_errno(db.getNativePointer()); @@ -1842,13 +1834,13 @@ public final class CApi { public static native int sqlite3_threadsafe(); - static native int sqlite3_total_changes(@NotNull long ptrToDb); + private static native int sqlite3_total_changes(@NotNull long ptrToDb); public static int sqlite3_total_changes(@NotNull sqlite3 db){ return sqlite3_total_changes(db.getNativePointer()); } - static native long sqlite3_total_changes64(@NotNull long ptrToDb); + private static native long sqlite3_total_changes64(@NotNull long ptrToDb); public static long sqlite3_total_changes64(@NotNull sqlite3 db){ return sqlite3_total_changes64(db.getNativePointer()); @@ -1871,7 +1863,7 @@ public final class CApi { @NotNull sqlite3 db, @Nullable String zSchema ); - static native UpdateHookCallback sqlite3_update_hook( + private static native UpdateHookCallback sqlite3_update_hook( @NotNull long ptrToDb, @Nullable UpdateHookCallback hook ); @@ -1891,67 +1883,67 @@ public final class CApi { sqlite3_create_function(). */ - static native byte[] sqlite3_value_blob(@NotNull long ptrToValue); + private static native byte[] sqlite3_value_blob(@NotNull long ptrToValue); public static byte[] sqlite3_value_blob(@NotNull sqlite3_value v){ return sqlite3_value_blob(v.getNativePointer()); } - static native int sqlite3_value_bytes(@NotNull long ptrToValue); + private static native int sqlite3_value_bytes(@NotNull long ptrToValue); public static int sqlite3_value_bytes(@NotNull sqlite3_value v){ return sqlite3_value_bytes(v.getNativePointer()); } - static native int sqlite3_value_bytes16(@NotNull long ptrToValue); + private static native int sqlite3_value_bytes16(@NotNull long ptrToValue); public static int sqlite3_value_bytes16(@NotNull sqlite3_value v){ return sqlite3_value_bytes16(v.getNativePointer()); } - static native double sqlite3_value_double(@NotNull long ptrToValue); + private static native double sqlite3_value_double(@NotNull long ptrToValue); public static double sqlite3_value_double(@NotNull sqlite3_value v){ return sqlite3_value_double(v.getNativePointer()); } - static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue); + private static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue); public static sqlite3_value sqlite3_value_dup(@NotNull sqlite3_value v){ return sqlite3_value_dup(v.getNativePointer()); } - static native int sqlite3_value_encoding(@NotNull long ptrToValue); + private static native int sqlite3_value_encoding(@NotNull long ptrToValue); public static int sqlite3_value_encoding(@NotNull sqlite3_value v){ return sqlite3_value_encoding(v.getNativePointer()); } - static native void sqlite3_value_free(@Nullable long ptrToValue); + private static native void sqlite3_value_free(@Nullable long ptrToValue); public static void sqlite3_value_free(@Nullable sqlite3_value v){ - sqlite3_value_free(v.getNativePointer()); + if( null!=v ) sqlite3_value_free(v.clearNativePointer()); } - static native boolean sqlite3_value_frombind(@NotNull long ptrToValue); + private static native boolean sqlite3_value_frombind(@NotNull long ptrToValue); public static boolean sqlite3_value_frombind(@NotNull sqlite3_value v){ return sqlite3_value_frombind(v.getNativePointer()); } - static native int sqlite3_value_int(@NotNull long ptrToValue); + private static native int sqlite3_value_int(@NotNull long ptrToValue); public static int sqlite3_value_int(@NotNull sqlite3_value v){ return sqlite3_value_int(v.getNativePointer()); } - static native long sqlite3_value_int64(@NotNull long ptrToValue); + private static native long sqlite3_value_int64(@NotNull long ptrToValue); public static long sqlite3_value_int64(@NotNull sqlite3_value v){ return sqlite3_value_int64(v.getNativePointer()); } - static native Object sqlite3_value_java_object(@NotNull long ptrToValue); + private static native Object sqlite3_value_java_object(@NotNull long ptrToValue); /** If the given value was set using {@link @@ -1977,25 +1969,25 @@ public final class CApi { return type.isInstance(o) ? (T)o : null; } - static native int sqlite3_value_nochange(@NotNull long ptrToValue); + private static native int sqlite3_value_nochange(@NotNull long ptrToValue); public static int sqlite3_value_nochange(@NotNull sqlite3_value v){ return sqlite3_value_nochange(v.getNativePointer()); } - static native int sqlite3_value_numeric_type(@NotNull long ptrToValue); + private static native int sqlite3_value_numeric_type(@NotNull long ptrToValue); public static int sqlite3_value_numeric_type(@NotNull sqlite3_value v){ return sqlite3_value_numeric_type(v.getNativePointer()); } - static native int sqlite3_value_subtype(@NotNull long ptrToValue); + private static native int sqlite3_value_subtype(@NotNull long ptrToValue); public static int sqlite3_value_subtype(@NotNull sqlite3_value v){ return sqlite3_value_subtype(v.getNativePointer()); } - static native byte[] sqlite3_value_text(@NotNull long ptrToValue); + private static native byte[] sqlite3_value_text(@NotNull long ptrToValue); /** Functions identially to the C API, and this note is just to @@ -2007,13 +1999,13 @@ public final class CApi { return sqlite3_value_text(v.getNativePointer()); } - static native String sqlite3_value_text16(@NotNull long ptrToValue); + private static native String sqlite3_value_text16(@NotNull long ptrToValue); public static String sqlite3_value_text16(@NotNull sqlite3_value v){ return sqlite3_value_text16(v.getNativePointer()); } - static native int sqlite3_value_type(@NotNull long ptrToValue); + private static native int sqlite3_value_type(@NotNull long ptrToValue); public static int sqlite3_value_type(@NotNull sqlite3_value v){ return sqlite3_value_type(v.getNativePointer()); diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3.java index 901317f0ef..cc6f2e6e8d 100644 --- a/ext/jni/src/org/sqlite/jni/capi/sqlite3.java +++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3.java @@ -38,6 +38,6 @@ public final class sqlite3 extends NativePointerHolder } @Override public void close(){ - CApi.sqlite3_close_v2(this.clearNativePointer()); + CApi.sqlite3_close_v2(this); } } diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java index 3b8b71f8a5..564891c727 100644 --- a/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java +++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java @@ -25,6 +25,6 @@ public final class sqlite3_stmt extends NativePointerHolder private sqlite3_stmt(){} @Override public void close(){ - CApi.sqlite3_finalize(this.clearNativePointer()); + CApi.sqlite3_finalize(this); } } diff --git a/manifest b/manifest index e1f54ab601..242ef22173 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Flesh\sout\s[7a63b5b65a79]\sto\sbe\sable\sto\sbuild\sJNI\swith\sor\swithout\sSQLITE_ENABLE_COLUMN_METADATA. -D 2023-11-07T13:22:49.498 +C Diverse\sminor\scleanups\sin\sthe\sJNI\spieces. +D 2023-11-07T13:44:29.266 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c ac7aa8ef250be4bebf99aa5b610d4a1b5f26578328a458a53db3b075271417ed +F ext/jni/src/c/sqlite3-jni.c 62455cadfc32d52c525b56c521467586a1704865556426cd648af642a770b6b6 F ext/jni/src/c/sqlite3-jni.h 9300900f7ec91fffa01445e1ad5815e35a7bece4c9ca07de464641f77195404a F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 75b92b98ee1e621e71466e4bdb3bdff580da688e9873524adffd97db12675eb1 +F ext/jni/src/org/sqlite/jni/capi/CApi.java 27e3c73685e1068e51331cd083152e0a6357b02278cb67b7c103240dbc262a5d F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -276,11 +276,11 @@ F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e -F ext/jni/src/org/sqlite/jni/capi/sqlite3.java 4010bbebc5bf44e2044e610786088cdee7dc155da2b333c0551492ff1cedf33b +F ext/jni/src/org/sqlite/jni/capi/sqlite3.java c6a5c555d163d76663534f2b2cce7cab15325b9852d0f58c6688a85e73ae52f0 F ext/jni/src/org/sqlite/jni/capi/sqlite3_backup.java 6742b431cd4d77e8000c1f92ec66265a58414c86bf3b0b5fbcb1164e08477227 F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java f204ab6ab1263e119fe43730141a00662d80972129a5351dfb11aae5d282df36 F ext/jni/src/org/sqlite/jni/capi/sqlite3_context.java f0ef982009c335c4393ffcb68051809ca1711e4f47bcb8d1d46952f22c01bc22 -F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java ff579621e9bd5ffbc6b2ef9f996c12db4df6e0c8cc5697c91273e5fca279fcf8 +F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java 293b5fa7d5b5724c87de544654aca1103d76f3092bc2c8f4360102a65ba25dff F ext/jni/src/org/sqlite/jni/capi/sqlite3_value.java e1d62a257c13504b46d39d5c21c49cf157ad73fda00cc5f34c931aa008c37049 F ext/jni/src/org/sqlite/jni/fts5/Fts5.java e94681023785f1eff5399f0ddc82f46b035977d350f14838db659236ebdf6b41 F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 338637e6e5a2cc385d962b220f3c1f475cc371d12ae43d18ef27327b6e6225f7 @@ -2142,8 +2142,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 7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a -R efbde6eb422be28e0f5c5e7a6eec616d +P fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901 +R 2e556ea528a12ae342b294a8936cf3da U stephan -Z adceda1b2796226e98fdf1b3f6f9cd13 +Z 63d82a638a6f714cab2831b5cda37824 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 26896fc11a..8908c89a68 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901 \ No newline at end of file +35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4 \ No newline at end of file From 488125d4ced1736963a35adabc42e4a0091a089c Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 7 Nov 2023 15:56:39 +0000 Subject: [PATCH 20/55] Add Sqlite.prepareMulti() to JNI wrapper1, for preparing multiple statements from a single input. FossilOrigin-Name: e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a --- ext/jni/src/org/sqlite/jni/capi/CApi.java | 12 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 127 ++++++++++++++++-- .../src/org/sqlite/jni/wrapper1/Tester2.java | 33 ++++- manifest | 16 +-- manifest.uuid | 2 +- 5 files changed, 166 insertions(+), 24 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 8bdcb3cf2d..1b08c50a28 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -1202,26 +1202,26 @@ public final class CApi { */ public static int sqlite3_prepare_multi( @NotNull sqlite3 db, @NotNull byte[] sqlUtf8, - int preFlags, + int prepFlags, @NotNull PrepareMultiCallback p){ final OutputPointer.Int32 oTail = new OutputPointer.Int32(); int pos = 0, n = 1; byte[] sqlChunk = sqlUtf8; int rc = 0; final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); - while(0==rc && pos 0){ + if( pos>0 ){ sqlChunk = Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length); } if( 0==sqlChunk.length ) break; - rc = sqlite3_prepare_v3(db, sqlChunk, preFlags, outStmt, oTail); + rc = sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail); if( 0!=rc ) break; pos = oTail.value; stmt = outStmt.take(); - if( null == stmt ){ - // empty statement was parsed. + if( null==stmt ){ + // empty statement (whitespace/comments) continue; } rc = p.call(stmt); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 93c294f5de..e61b7e59dd 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -510,19 +510,27 @@ public final class Sqlite implements AutoCloseable { } /** + Analog to sqlite3_prepare_v3(), this prepares the first SQL + statement from the given input string and returns it as a + Stmt. It throws an SqliteException if preparation fails or an + IllegalArgumentException if the input is empty (e.g. contains + only comments or whitespace). + + The first argument must be SQL input in UTF-8 encoding. + prepFlags must be 0 or a bitmask of the PREPARE_... constants. - prepare() TODOs include: + For processing multiple statements from a single input, use + prepareMulti(). - - overloads taking byte[] and ByteBuffer. - - - multi-statement processing, like CApi.sqlite3_prepare_multi() - but using a callback specific to the higher-level Stmt class - rather than the sqlite3_stmt class. + Design note: though the C-level API succeeds with a null + statement object for empty inputs, that approach is cumbersome to + use in higher-level APIs because every prepared statement has to + be checked for null before using it. */ - public Stmt prepare(String sql, int prepFlags){ + public Stmt prepare(byte utf8Sql[], int prepFlags){ final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt(); - final int rc = CApi.sqlite3_prepare_v3(thisDb(), sql, prepFlags, out); + final int rc = CApi.sqlite3_prepare_v3(thisDb(), utf8Sql, prepFlags, out); checkRc(rc); final sqlite3_stmt q = out.take(); if( null==q ){ @@ -539,10 +547,113 @@ public final class Sqlite implements AutoCloseable { return new Stmt(this, q); } + /** + Equivalent to prepare(X, prepFlags), where X is + sql.getBytes(StandardCharsets.UTF_8). + */ + public Stmt prepare(String sql, int prepFlags){ + return prepare( sql.getBytes(StandardCharsets.UTF_8), prepFlags ); + } + + /** + Equivalent to prepare(sql, 0). + */ public Stmt prepare(String sql){ return prepare(sql, 0); } + + /** + Callback type for use with prepareMulti(). + */ + public interface PrepareMulti { + /** + Gets passed a Stmt which it may handle in arbitrary ways. + Ownership of st is passed to this function. It must throw on + error. + */ + void call(Sqlite.Stmt st); + } + + /** + A PrepareMulti implementation which calls another PrepareMulti + object and then finalizes its statement. + */ + public static class PrepareMultiFinalize implements PrepareMulti { + private final PrepareMulti pm; + /** + Proxies the given PrepareMulti via this object's call() method. + */ + public PrepareMultiFinalize(PrepareMulti proxy){ + this.pm = proxy; + } + /** + Passes st to the call() method of the object this one proxies, + then finalizes st, propagating any exceptions from call() after + finalizing st. + */ + @Override public void call(Stmt st){ + try{ pm.call(st); } + finally{ st.finalizeStmt(); } + } + } + + /** + Equivalent to prepareMulti(sql,0,visitor). + */ + public void prepareMulti(String sql, PrepareMulti visitor){ + prepareMulti( sql, 0, visitor ); + } + + /** + A variant of prepare() which can handle multiple SQL statements + in a single input string. For each statement in the given string, + the statement is passed to visitor.call() a single time, passing + ownership of the statement to that function. This function does + not step() or close() statements - those operations are left to + caller or the visitor function. + + Unlike prepare(), this function does not fail if the input + contains only whitespace or SQL comments. In that case it is up + to the caller to arrange for that to be an error (if desired). + + PrepareMultiFinalize offers a proxy which finalizes each + statement after it is passed to another client-defined visitor. + */ + public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){ + int pos = 0, n = 1; + byte[] sqlChunk = sqlUtf8; + final org.sqlite.jni.capi.OutputPointer.sqlite3_stmt outStmt = + new org.sqlite.jni.capi.OutputPointer.sqlite3_stmt(); + final org.sqlite.jni.capi.OutputPointer.Int32 oTail = + new org.sqlite.jni.capi.OutputPointer.Int32(); + while( pos < sqlChunk.length ){ + sqlite3_stmt stmt = null; + if( pos>0 ){ + sqlChunk = java.util.Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length); + } + if( 0==sqlChunk.length ) break; + checkRc( + CApi.sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail) + ); + pos = oTail.value; + stmt = outStmt.take(); + if( null==stmt ){ + /* empty statement, e.g. only comments or whitespace, was parsed. */ + continue; + } + visitor.call(new Stmt(this, stmt)); + } + } + + /** + Equivallent to prepareMulti(X,prepFlags,visitor), where X is + sql.getBytes(StandardCharsets.UTF_8). + */ + public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){ + prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor); + } + public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){ int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep, new SqlFunction.ScalarAdapter(f)); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 3f7593c709..c7566b3b0f 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -125,7 +125,7 @@ public class Tester2 implements Runnable { } - public static void execSql(Sqlite db, String[] sql){ + public static void execSql(Sqlite db, String sql[]){ execSql(db, String.join("", sql)); } @@ -938,6 +938,37 @@ public class Tester2 implements Runnable { db.close(); } + void testPrepareMulti(){ + final ValueHolder fCount = new ValueHolder<>(0); + final ValueHolder mCount = new ValueHolder<>(0); + try (Sqlite db = openDb()) { + execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)"); + db.createFunction("counter", -1, new ScalarFunction(){ + @Override public void xFunc(SqlFunction.Arguments args){ + ++fCount.value; + args.resultNull(); + } + public void xDestroy(){} + } + ); + final Sqlite.PrepareMulti pm = new Sqlite.PrepareMultiFinalize( + new Sqlite.PrepareMulti() { + @Override public void call(Sqlite.Stmt q){ + ++mCount.value; + while(q.step()){} + } + } + ); + final String sql = "select counter(*) from t;"+ + "select counter(*) from t; /* comment */"+ + "select counter(*) from t; -- comment\n" + ; + db.prepareMulti(sql, pm); + } + affirm( 3 == mCount.value ); + affirm( 9 == fCount.value ); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/manifest b/manifest index 242ef22173..003a80d74a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Diverse\sminor\scleanups\sin\sthe\sJNI\spieces. -D 2023-11-07T13:44:29.266 +C Add\sSqlite.prepareMulti()\sto\sJNI\swrapper1,\sfor\spreparing\smultiple\sstatements\sfrom\sa\ssingle\sinput. +D 2023-11-07T15:56:39.576 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 27e3c73685e1068e51331cd083152e0a6357b02278cb67b7c103240dbc262a5d +F ext/jni/src/org/sqlite/jni/capi/CApi.java 170cfd6501f6a4e68073808f3046970a6dd73d2faf478cbc9bd23f159ff3a646 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 6a310fe422d0daf79f7841c9b341f64d843ca7e85ef31829530623a81ecd25fa +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java a944fd0a9047a51a5074bffd707452d80cf06e715ebc78b541480ee98629fb93 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 2ecf37746f2d475a133b530ddaf9ba8a6a65ce238db0805cb8e410ee760d4793 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901 -R 2e556ea528a12ae342b294a8936cf3da +P 35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4 +R e808fc8487495cabb8d32f4b1af8109a U stephan -Z 63d82a638a6f714cab2831b5cda37824 +Z 28ef3e488a5683b53a25a3e0e53067e7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8908c89a68..612e2ef446 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4 \ No newline at end of file +e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a \ No newline at end of file From 637922acac23fe995fd2772559eaf5b75d057c9b Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 7 Nov 2023 17:15:55 +0000 Subject: [PATCH 21/55] JNI: during static init record whether the current JVM supports JNI-level access to java.nio.ByteBuffer raw memory, and add sqlite3_jni_supports_nio() to query that. FossilOrigin-Name: fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9 --- ext/jni/src/c/sqlite3-jni.c | 45 +++++++++++++------ ext/jni/src/c/sqlite3-jni.h | 8 ++++ ext/jni/src/org/sqlite/jni/capi/CApi.java | 6 +++ ext/jni/src/org/sqlite/jni/capi/Tester1.java | 1 + .../src/org/sqlite/jni/wrapper1/Tester2.java | 1 - manifest | 20 ++++----- manifest.uuid | 2 +- 7 files changed, 57 insertions(+), 26 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 852b0ccceb..7519dfb6c0 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -651,6 +651,17 @@ struct S3JniGlobalType { jmethodID ctorLong1 /* the Long(long) constructor */; jmethodID ctorStringBA /* the String(byte[],Charset) constructor */; jmethodID stringGetBytes /* the String.getBytes(Charset) method */; + + /* + ByteBuffer may or may not be supported via JNI on any given + platform: + + https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#nio_support + + We only store a ref to the following if JNI support for + ByteBuffer is available (which we determine during static init). + */ + jclass cByteBuffer /* global ref to java.nio.ByteBuffer */; } g; /* ** The list of Java-side auto-extensions @@ -3661,6 +3672,11 @@ JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){ return rc ? JNI_TRUE : JNI_FALSE; } +JniDecl(jboolean,1jni_1supports_1nio)(JniArgsEnvClass){ + return SJG.g.cByteBuffer ? JNI_TRUE : JNI_FALSE; +} + + S3JniApi(sqlite3_keyword_check(),jboolean,1keyword_1check)( JniArgsEnvClass, jstring jWord ){ @@ -4576,20 +4592,8 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)( S3JniEnv_uncache( SJG.envCache.aHead->env ); } } S3JniEnv_mutex_leave; -#if 0 - /* - ** Is automatically closing any still-open dbs a good idea? We will - ** get rid of the perDb list once sqlite3 gets a per-db client - ** state, at which point we won't have a central list of databases - ** to close. - */ - S3JniDb_mutex_enter; - while( SJG.perDb.pHead ){ - s3jni_close_db(env, SJG.perDb.pHead->jDb, 2); - } - S3JniDb_mutex_leave; -#endif - /* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */ + /* Do not clear S3JniGlobal.jvm or S3JniGlobal.g: it's legal to + ** restart the lib. */ return sqlite3_shutdown(); } @@ -5930,6 +5934,19 @@ Java_org_sqlite_jni_capi_CApi_init(JniArgsEnvClass){ s3jni_oom_fatal( SJG.metrics.mutex ); #endif + { + /* Test whether this JVM supports direct memory access via + ByteBuffer. */ + unsigned char buf[16] = {0}; + jobject bb = (*env)->NewDirectByteBuffer(env, buf, 16); + if( bb ){ + SJG.g.cByteBuffer = (*env)->GetObjectClass(env, bb); + S3JniUnrefLocal(bb); + }else{ + SJG.g.cByteBuffer = 0; + } + } + sqlite3_shutdown() /* So that it becomes legal for Java-level code to call ** sqlite3_config(). */; diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index c4ca0559f2..f160b6453f 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -773,6 +773,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_init JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_1thread (JNIEnv *, jclass); +/* + * Class: org_sqlite_jni_capi_CApi + * Method: sqlite3_jni_supports_nio + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio + (JNIEnv *, jclass); + /* * Class: org_sqlite_jni_capi_CApi * Method: sqlite3_aggregate_context diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 1b08c50a28..8e0cb8f4aa 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -123,6 +123,12 @@ public final class CApi { */ public static native boolean sqlite3_java_uncache_thread(); + /** + Returns true if this JVM has JNI-level support for direct memory + access using java.nio.ByteBuffer, else returns false. + */ + public static native boolean sqlite3_jni_supports_nio(); + ////////////////////////////////////////////////////////////////////// // Maintenance reminder: please keep the sqlite3_.... functions // alphabetized. The SQLITE_... values. on the other hand, are diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index f11a644a3b..3ac58c67d3 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -1920,6 +1920,7 @@ public class Tester1 implements Runnable { sqlite3_libversion_number(),"\n", sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n", "SQLITE_THREADSAFE=",sqlite3_threadsafe()); + outln("JVM NIO support? ",sqlite3_jni_supports_nio() ? "YES" : "NO"); final boolean showLoopCount = (nRepeat>1 && nThread>1); if( showLoopCount ){ outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each."); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index c7566b3b0f..c276e383be 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -948,7 +948,6 @@ public class Tester2 implements Runnable { ++fCount.value; args.resultNull(); } - public void xDestroy(){} } ); final Sqlite.PrepareMulti pm = new Sqlite.PrepareMultiFinalize( diff --git a/manifest b/manifest index 003a80d74a..4a41fc1505 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sSqlite.prepareMulti()\sto\sJNI\swrapper1,\sfor\spreparing\smultiple\sstatements\sfrom\sa\ssingle\sinput. -D 2023-11-07T15:56:39.576 +C JNI:\sduring\sstatic\sinit\srecord\swhether\sthe\scurrent\sJVM\ssupports\sJNI-level\saccess\sto\sjava.nio.ByteBuffer\sraw\smemory,\sand\sadd\ssqlite3_jni_supports_nio()\sto\squery\sthat. +D 2023-11-07T17:15:55.097 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,8 +241,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 62455cadfc32d52c525b56c521467586a1704865556426cd648af642a770b6b6 -F ext/jni/src/c/sqlite3-jni.h 9300900f7ec91fffa01445e1ad5815e35a7bece4c9ca07de464641f77195404a +F ext/jni/src/c/sqlite3-jni.c aac355ea590199dcbc8ef765f702ee616c90504528c812a37605a0d0994b1b23 +F ext/jni/src/c/sqlite3-jni.h 18925c56d6664fdec081c56daf3b2ffa0e0ff6b9b128b9f39b84862f34ba0601 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 170cfd6501f6a4e68073808f3046970a6dd73d2faf478cbc9bd23f159ff3a646 +F ext/jni/src/org/sqlite/jni/capi/CApi.java 16a28138c3c25f33356193970644389ff8ebc0720499549653934b2529c8d1dd F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385 F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java bcfc48cba038e8dc6e08cb9b8a974241e5d9920ab4015c3abf482b7130ac9ba4 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java b1a0c015d92a8d0c07a8f6751e9b057557cec9d803e002d48ee5f3b9963abd55 F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56 F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950 @@ -298,7 +298,7 @@ F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaac F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 2ecf37746f2d475a133b530ddaf9ba8a6a65ce238db0805cb8e410ee760d4793 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 @@ -2142,8 +2142,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 35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4 -R e808fc8487495cabb8d32f4b1af8109a +P e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a +R 73b75ed4c87333bbc1b63a547227eff1 U stephan -Z 28ef3e488a5683b53a25a3e0e53067e7 +Z ff630bf6abb02dbe33113baf6eccc049 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 612e2ef446..997a53ff67 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a \ No newline at end of file +fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9 \ No newline at end of file From 17a32953873c52b91a18f79f371bd15887a022ed Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 7 Nov 2023 19:03:13 +0000 Subject: [PATCH 22/55] Update the documentation to the sqlite3_set_auxdata() and sqlite3_get_auxdata() routines to make it clear that they do not work as one might expect when they are called during query planning, instead of during query execution. The JSON routines misuse those interfaces, so add a special flag to JSON routines that prevents them from being invoked during query planning. Fix for the problem in [forum:/forumpost/a655ee159eca1ea5|forum post a655ee159eca1ea5]. FossilOrigin-Name: 796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/sqlite.h.in | 14 +++++++++++--- src/sqliteInt.h | 4 ++-- src/vdbemem.c | 2 +- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 4a41fc1505..1c358844a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JNI:\sduring\sstatic\sinit\srecord\swhether\sthe\scurrent\sJVM\ssupports\sJNI-level\saccess\sto\sjava.nio.ByteBuffer\sraw\smemory,\sand\sadd\ssqlite3_jni_supports_nio()\sto\squery\sthat. -D 2023-11-07T17:15:55.097 +C Update\sthe\sdocumentation\sto\sthe\ssqlite3_set_auxdata()\sand\ssqlite3_get_auxdata()\nroutines\sto\smake\sit\sclear\sthat\sthey\sdo\snot\swork\sas\sone\smight\sexpect\swhen\sthey\nare\scalled\sduring\squery\splanning,\sinstead\sof\sduring\squery\sexecution.\s\sThe\sJSON\nroutines\smisuse\sthose\sinterfaces,\sso\sadd\sa\sspecial\sflag\sto\sJSON\sroutines\sthat\nprevents\sthem\sfrom\sbeing\sinvoked\sduring\squery\splanning.\s\sFix\sfor\sthe\sproblem\nin\s[forum:/forumpost/a655ee159eca1ea5|forum\spost\sa655ee159eca1ea5]. +D 2023-11-07T19:03:13.268 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -726,10 +726,10 @@ F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 F src/shell.c.in aebfbedaa7706d2c73ab7366a19fc8bc40ea68b70d2529f7feef54e6eb077ea2 -F src/sqlite.h.in ef0e41e83ad1ac0dcc9ec9939bf541a44b1c5de821bee2d6c61754c3252f3276 +F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h 707095a0591e02f4866ed9798cbdd97a8ae8cf4d98f061808944c2cd1c95d1a9 +F src/sqliteInt.h b9f6cfac999b60def4d3523897dc1f5453ab9c24195e462fd346476541cf659a F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -800,7 +800,7 @@ F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c F src/vdbeapi.c db190d007bdf5b9165edeb12369f4c59a459f88fd652c1671c1238862e662cc3 F src/vdbeaux.c dffcf79e7e415fcd6e4c8ac1ec7124cae5257018443adf09551c807655b04993 F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5 -F src/vdbemem.c c936e9002af4993b84c4eb7133d6b1190efe46d391cc86117ecd67ba17b1a04b +F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0 F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7 @@ -2142,8 +2142,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 e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a -R 73b75ed4c87333bbc1b63a547227eff1 -U stephan -Z ff630bf6abb02dbe33113baf6eccc049 +P fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9 +R 153ffbf9f72d490791b9001d5155efbf +U drh +Z f301b7ed97efe53d235a7cee46d075cc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 997a53ff67..1267d0d18b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9 \ No newline at end of file +796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 01a7f4d4e0..2317d98f79 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5913,14 +5913,22 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); **

  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
  • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^ +** allocation error occurs.)^ +**
  • ^(during the original sqlite3_set_auxdata() call if the function +** is evaluated during query planning instead of during query execution, +** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ ** -** Note the last bullet in particular. The destructor X in +** Note the last two bullets in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. +** sqlite3_set_auxdata() has been called. Furthermore, a call to +** sqlite3_get_auxdata() that occurs immediately after a corresponding call +** to sqlite3_set_auxdata() might still return NULL if an out-of-memory +** condition occurred during the sqlite3_set_auxdata() call or if the +** function is being evaluated during query planning rather than during +** query execution. ** ** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 23beb48de3..1a22500539 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2014,7 +2014,7 @@ struct FuncDestructor { #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ -/* 0x8000 -- available for reuse */ +#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ @@ -2115,7 +2115,7 @@ struct FuncDestructor { xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } #define JFUNCTION(zName, nArg, iArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\ - SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|SQLITE_FUNC_RUNONLY, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ diff --git a/src/vdbemem.c b/src/vdbemem.c index eee828143a..d527164685 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1515,7 +1515,7 @@ static int valueFromFunction( #endif assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 - || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0 ){ return SQLITE_OK; } From 344255e5aaddbb5b9ba5aba44d7aea124baec1b5 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 7 Nov 2023 19:39:23 +0000 Subject: [PATCH 23/55] An attempt to work around compilation errors on MinGW reported in [forum:9089d2049a|forum post 9089d2049a]. FossilOrigin-Name: d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8 --- ext/jni/src/c/sqlite3-jni.c | 4 ++-- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 7519dfb6c0..9f44ecdbd0 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -201,8 +201,8 @@ ** ** https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers */ -#define JniArgsEnvObj JNIEnv * const env, jobject jSelf -#define JniArgsEnvClass JNIEnv * const env, jclass jKlazz +#define JniArgsEnvObj JNIEnv * env, jobject jSelf +#define JniArgsEnvClass JNIEnv * env, jclass jKlazz /* ** Helpers to account for -Xcheck:jni warnings about not having ** checked for exceptions. diff --git a/manifest b/manifest index 1c358844a5..099e8a1a6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\sdocumentation\sto\sthe\ssqlite3_set_auxdata()\sand\ssqlite3_get_auxdata()\nroutines\sto\smake\sit\sclear\sthat\sthey\sdo\snot\swork\sas\sone\smight\sexpect\swhen\sthey\nare\scalled\sduring\squery\splanning,\sinstead\sof\sduring\squery\sexecution.\s\sThe\sJSON\nroutines\smisuse\sthose\sinterfaces,\sso\sadd\sa\sspecial\sflag\sto\sJSON\sroutines\sthat\nprevents\sthem\sfrom\sbeing\sinvoked\sduring\squery\splanning.\s\sFix\sfor\sthe\sproblem\nin\s[forum:/forumpost/a655ee159eca1ea5|forum\spost\sa655ee159eca1ea5]. -D 2023-11-07T19:03:13.268 +C An\sattempt\sto\swork\saround\scompilation\serrors\son\sMinGW\sreported\sin\s[forum:9089d2049a|forum\spost\s9089d2049a]. +D 2023-11-07T19:39:23.562 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c aac355ea590199dcbc8ef765f702ee616c90504528c812a37605a0d0994b1b23 +F ext/jni/src/c/sqlite3-jni.c 7c6d944799c12eebc32ecf9e21ec40f1060fbcb77a9c1faef569f1e7770a938d F ext/jni/src/c/sqlite3-jni.h 18925c56d6664fdec081c56daf3b2ffa0e0ff6b9b128b9f39b84862f34ba0601 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -2142,8 +2142,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 fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9 -R 153ffbf9f72d490791b9001d5155efbf -U drh -Z f301b7ed97efe53d235a7cee46d075cc +P 796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b +R 86b853f71a942ef4a14b3758cd2ed59f +U stephan +Z 12a762f4452f720d39ec9297cb5542a9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1267d0d18b..9071024677 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b \ No newline at end of file +d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8 \ No newline at end of file From 275234e3206758df0143dad63cf7aa8802c317f9 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 7 Nov 2023 20:11:49 +0000 Subject: [PATCH 24/55] Fix an assert() that could fail within calls to sqlite3_snapshot_open() in SQLITE_ENABLE_SETLK_TIMEOUT builds. FossilOrigin-Name: 84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/os_unix.c | 15 +++++++++------ test/snapshot_up.test | 2 ++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 099e8a1a6d..2b98b89df2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C An\sattempt\sto\swork\saround\scompilation\serrors\son\sMinGW\sreported\sin\s[forum:9089d2049a|forum\spost\s9089d2049a]. -D 2023-11-07T19:39:23.562 +C Fix\san\sassert()\sthat\scould\sfail\swithin\scalls\sto\ssqlite3_snapshot_open()\sin\sSQLITE_ENABLE_SETLK_TIMEOUT\sbuilds. +D 2023-11-07T20:11:49.770 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -708,7 +708,7 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06 F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107 -F src/os_unix.c cb116fde9e3ca3c1bbfdf89d6928f776a2a34da168e2667426523a4db353b271 +F src/os_unix.c 0a33005e6426702c7e76f3d451f296c088693a95b2be28ba9ef59c8d8529ce6b F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 699aab8dfc88056d796b03b40c0ab979040d58dfc3ae9db207f1be91e4880bbf @@ -1587,7 +1587,7 @@ F test/snapshot2.test 8d6ff5dd9cc503f6e12d408a30409c3f9c653507b24408d9cd7195931c F test/snapshot3.test 8744313270c55f6e18574283553d3c5c5fe4c5970585663613a0e75c151e599b F test/snapshot4.test d4e9347ef2fcabc491fc893506c7bbaf334da3be111d6eb4f3a97cc623b78322 F test/snapshot_fault.test 129234ceb9b26a0e1000e8563a16e790f5c1412354e70749cbd78c3d5d07d60a -F test/snapshot_up.test a0a29c4cf33475fcef07c3f8e64af795e24ab91b4cc68295863402a393cdd41c +F test/snapshot_up.test 77dc7853bfb2b4fa249f76e1714cfa1e596826165d9ef22c06ac3a0b7b778d9a F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087 F test/sort.test f86751134159abb5e5fd4381a0d7038c91013638cd1e3fa1d7850901f6df6196 @@ -2142,8 +2142,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 796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b -R 86b853f71a942ef4a14b3758cd2ed59f -U stephan -Z 12a762f4452f720d39ec9297cb5542a9 +P d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8 +R 51ac3a4b6cfe47fd7ec11d417bc30543 +U dan +Z d5bc56d23e981b8dfdb9cdcebdb1ac5d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9071024677..cad3be627e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8 \ No newline at end of file +84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index a33e6f4dff..cd3e0fc54d 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4980,12 +4980,15 @@ static int unixShmLock( ** It is not permitted to block on the RECOVER lock. */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( - (ofst!=2) /* not RECOVER */ - && (ofst!=1 || (p->exclMask|p->sharedMask)==0) - && (ofst!=0 || (p->exclMask|p->sharedMask)<3) - && (ofst<3 || (p->exclMask|p->sharedMask)<(1<exclMask|p->sharedMask); + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( + (ofst!=2) /* not RECOVER */ + && (ofst!=1 || lockMask==0 || lockMask==2) + && (ofst!=0 || lockMask<3) + && (ofst<3 || lockMask<(1< Date: Tue, 7 Nov 2023 20:56:29 +0000 Subject: [PATCH 25/55] Add -DSQLITE_ENABLE_SETLK_TIMEOUT=1 to a release-test configuration. FossilOrigin-Name: cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/releasetest_data.tcl | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 2b98b89df2..81edb7cb38 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sassert()\sthat\scould\sfail\swithin\scalls\sto\ssqlite3_snapshot_open()\sin\sSQLITE_ENABLE_SETLK_TIMEOUT\sbuilds. -D 2023-11-07T20:11:49.770 +C Add\s-DSQLITE_ENABLE_SETLK_TIMEOUT=1\sto\sa\srelease-test\sconfiguration. +D 2023-11-07T20:56:29.493 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1487,7 +1487,7 @@ F test/recover.test fd5199f928757cb308661b5fdca1abc19398a798ff7f24b57c3071e9f8e0 F test/regexp1.test 8f2a8bc1569666e29a4cee6c1a666cd224eb6d50e2470d1dc1df995170f3e0f1 F test/regexp2.test 55ed41da802b0e284ac7e2fe944be3948f93ff25abbca0361a609acfed1368b5 F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d -F test/releasetest_data.tcl 80ef3941bf7ad136f4dc3d8960786f10a4f488797238171bdd757cc6eb4c3efa +F test/releasetest_data.tcl 50679c8de0e67ca93a47dc95fdf077ecbc4b6eceb14dcb76f19779ab44132e65 F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3 F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/returning1.test db532cde29d6aebbc48c6ddc3149b30476f8e69ca7a2c4b53986c7635e6fd8ec @@ -2142,8 +2142,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 d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8 -R 51ac3a4b6cfe47fd7ec11d417bc30543 +P 84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b +R abb9ab70d79eb8c8383bcdc7ce649ea3 U dan -Z d5bc56d23e981b8dfdb9cdcebdb1ac5d +Z 13575d6d42a1cdb37a2cb5cc87a1058f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cad3be627e..577b0790b1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b \ No newline at end of file +cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b \ No newline at end of file diff --git a/test/releasetest_data.tcl b/test/releasetest_data.tcl index 4ed57a9c8e..95c1b7af19 100644 --- a/test/releasetest_data.tcl +++ b/test/releasetest_data.tcl @@ -221,6 +221,7 @@ array set ::Configs [strip_comments { -DSQLITE_ENABLE_PERSIST_WAL=1 -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 -DSQLITE_ENABLE_RTREE=1 + -DSQLITE_ENABLE_SETLK_TIMEOUT=1 -DSQLITE_ENABLE_SNAPSHOT=1 # -DSQLITE_ENABLE_SQLLOG=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 From ec8f893e065c95a082e1e432bcacd4641ae8b13e Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Nov 2023 00:12:38 +0000 Subject: [PATCH 26/55] Changes a no-op call to freeP4() into an assert(). FossilOrigin-Name: 32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbeaux.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 81edb7cb38..500b44aadc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\s-DSQLITE_ENABLE_SETLK_TIMEOUT=1\sto\sa\srelease-test\sconfiguration. -D 2023-11-07T20:56:29.493 +C Changes\sa\sno-op\scall\sto\sfreeP4()\sinto\san\sassert(). +D 2023-11-08T00:12:38.510 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -798,7 +798,7 @@ F src/vdbe.c 14479441337135eed8e290fb1d4abb7db657d93217a3b1ea8a2f031d3895536a F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c F src/vdbeapi.c db190d007bdf5b9165edeb12369f4c59a459f88fd652c1671c1238862e662cc3 -F src/vdbeaux.c dffcf79e7e415fcd6e4c8ac1ec7124cae5257018443adf09551c807655b04993 +F src/vdbeaux.c f3997b5956c8d97bd2fc3392db42caecddfa6549e9df82e0a7e5804653ca475a F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5 F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0 F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547 @@ -2142,8 +2142,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 84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b -R abb9ab70d79eb8c8383bcdc7ce649ea3 -U dan -Z 13575d6d42a1cdb37a2cb5cc87a1058f +P cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b +R b6c8804aadc6653e2e6af22ab7efdb56 +U drh +Z 1be7d8d52cecb1d54f8658da7683cb85 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 577b0790b1..e8520c881c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b \ No newline at end of file +32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 54317b816f..1d9921b193 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1526,7 +1526,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full( int n ){ if( pOp->p4type ){ - freeP4(p->db, pOp->p4type, pOp->p4.p); + assert( pOp->p4type > P4_FREE_IF_LE ); pOp->p4type = 0; pOp->p4.p = 0; } From c78d3b59637449bc1c7dc4415e6e49ee9e52d156 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Nov 2023 00:45:14 +0000 Subject: [PATCH 27/55] Suppress harmless UBSAN warnings about memory overflow in OP_AddImm. The exact same machine code is generated by GCC. FossilOrigin-Name: b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbe.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 500b44aadc..01a9a1b873 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sa\sno-op\scall\sto\sfreeP4()\sinto\san\sassert(). -D 2023-11-08T00:12:38.510 +C Suppress\sharmless\sUBSAN\swarnings\sabout\smemory\soverflow\sin\sOP_AddImm.\s\sThe\nexact\ssame\smachine\scode\sis\sgenerated\sby\sGCC. +D 2023-11-08T00:45:14.192 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -794,7 +794,7 @@ F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c b22cc9f203a8c0b9ee5338a67f8860347d14845864c10248bebe84518a781677 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 -F src/vdbe.c 14479441337135eed8e290fb1d4abb7db657d93217a3b1ea8a2f031d3895536a +F src/vdbe.c 7034cf3eec0c905df753368efbcdd96377fca0245584e66766ec47a29fe468c8 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c F src/vdbeapi.c db190d007bdf5b9165edeb12369f4c59a459f88fd652c1671c1238862e662cc3 @@ -2142,8 +2142,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 cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b -R b6c8804aadc6653e2e6af22ab7efdb56 +P 32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d +R 018fee29b67a9c300c9a1c8f38582550 U drh -Z 1be7d8d52cecb1d54f8658da7683cb85 +Z d4e9689751359f866f309e9e035b0a5f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e8520c881c..7d15d1be9a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d \ No newline at end of file +b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 221e8847db..544c8d8457 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2033,7 +2033,7 @@ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); sqlite3VdbeMemIntegerify(pIn1); - pIn1->u.i += pOp->p2; + *(u64*)&pIn1->u.i += (u64)pOp->p2; break; } From 86b1898cb438fe312efa073cbf42ba44d8cd1d92 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 8 Nov 2023 12:56:23 +0000 Subject: [PATCH 28/55] JNI build fixes for platforms where the jint type is not the same as int, as reported in [forum:9089d2049a|forum post 9089d2049a]. FossilOrigin-Name: b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d --- ext/jni/src/c/sqlite3-jni.c | 20 ++++++++++---------- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 9f44ecdbd0..9384fb9d21 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -3061,7 +3061,7 @@ S3JniApi(sqlite3_compileoption_used(),jboolean,1compileoption_1used)( return rc; } -S3JniApi(sqlite3_complete(),int,1complete)( +S3JniApi(sqlite3_complete(),jint,1complete)( JniArgsEnvClass, jbyteArray jSql ){ jbyte * const pBuf = s3jni_jbyteArray_bytes(jSql); @@ -3507,7 +3507,7 @@ S3JniApi(sqlite3_db_readonly(),jint,1db_1readonly)( return (jint)rc; } -S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)( +S3JniApi(sqlite3_db_release_memory(),jint,1db_1release_1memory)( JniArgsEnvClass, jobject jDb ){ sqlite3 * const pDb = PtrGet_sqlite3(jDb); @@ -4012,11 +4012,11 @@ static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb, #if !defined(SQLITE_ENABLE_PREUPDATE_HOOK) /* We need no-op impls for preupdate_{count,depth,blobwrite}() */ -S3JniApi(sqlite3_preupdate_blobwrite(),int,1preupdate_1blobwrite)( +S3JniApi(sqlite3_preupdate_blobwrite(),jint,1preupdate_1blobwrite)( JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; } -S3JniApi(sqlite3_preupdate_count(),int,1preupdate_1count)( +S3JniApi(sqlite3_preupdate_count(),jint,1preupdate_1count)( JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; } -S3JniApi(sqlite3_preupdate_depth(),int,1preupdate_1depth)( +S3JniApi(sqlite3_preupdate_depth(),jint,1preupdate_1depth)( JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; } #endif /* !SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -4332,7 +4332,7 @@ S3JniApi(sqlite3_result_double(),void,1result_1double)( } S3JniApi(sqlite3_result_error(),void,1result_1error)( - JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, int eTextRep + JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, jint eTextRep ){ const char * zUnspecified = "Unspecified error."; jsize const baLen = (*env)->GetArrayLength(env, baMsg); @@ -4680,7 +4680,7 @@ S3JniApi(sqlite3_step(),jint,1step)( return pStmt ? (jint)sqlite3_step(pStmt) : (jint)SQLITE_MISUSE; } -S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)( +S3JniApi(sqlite3_table_column_metadata(),jint,1table_1column_1metadata)( JniArgsEnvClass, jobject jDb, jstring jDbName, jstring jTableName, jstring jColumnName, jobject jDataType, jobject jCollSeq, jobject jNotNull, jobject jPrimaryKey, jobject jAutoinc @@ -4866,14 +4866,14 @@ S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)( : NULL; } -S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)( +S3JniApi(sqlite3_value_bytes(),jint,1value_1bytes)( JniArgsEnvClass, jlong jpSVal ){ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); return sv ? sqlite3_value_bytes(sv) : 0; } -S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)( +S3JniApi(sqlite3_value_bytes16(),jint,1value_1bytes16)( JniArgsEnvClass, jlong jpSVal ){ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal); @@ -5540,7 +5540,7 @@ JniDeclFtsXA(jlong,xRowid)(JniArgsEnvObj,jobject jCtx){ return (jlong)ext->xRowid(PtrGet_Fts5Context(jCtx)); } -JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){ +JniDeclFtsXA(jint,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){ Fts5ExtDecl; int rc; S3JniFts5AuxData * pAux; diff --git a/manifest b/manifest index 01a9a1b873..7fcaaf8277 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Suppress\sharmless\sUBSAN\swarnings\sabout\smemory\soverflow\sin\sOP_AddImm.\s\sThe\nexact\ssame\smachine\scode\sis\sgenerated\sby\sGCC. -D 2023-11-08T00:45:14.192 +C JNI\sbuild\sfixes\sfor\splatforms\swhere\sthe\sjint\stype\sis\snot\sthe\ssame\sas\sint,\sas\sreported\sin\s[forum:9089d2049a|forum\spost\s9089d2049a]. +D 2023-11-08T12:56:23.623 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,7 +241,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 7c6d944799c12eebc32ecf9e21ec40f1060fbcb77a9c1faef569f1e7770a938d +F ext/jni/src/c/sqlite3-jni.c 6b95974189d7cc394afbe15507050f1d174170a65be5a4dad201ab11f0a9777a F ext/jni/src/c/sqlite3-jni.h 18925c56d6664fdec081c56daf3b2ffa0e0ff6b9b128b9f39b84862f34ba0601 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba @@ -2142,8 +2142,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 32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d -R 018fee29b67a9c300c9a1c8f38582550 -U drh -Z d4e9689751359f866f309e9e035b0a5f +P b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306 +R 3f46c0761970583c9dda3b5c30472d0c +U stephan +Z b9bb3a53ca08337ab5c86e3c35fc1299 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7d15d1be9a..d465a17824 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306 \ No newline at end of file +b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d \ No newline at end of file From 8657eddcdbda916c4f2cfe6cffe1ca7e712ad75c Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 8 Nov 2023 15:34:03 +0000 Subject: [PATCH 29/55] Remove an unused/invalid test from the wasm suite. FossilOrigin-Name: 916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502 --- ext/wasm/tester1.c-pp.js | 24 +----------------------- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js index c26bce25be..36ca4c976f 100644 --- a/ext/wasm/tester1.c-pp.js +++ b/ext/wasm/tester1.c-pp.js @@ -1688,7 +1688,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule; wasm.sqlite3_wasm_vfs_unlink(0, filename); } } - }/*sqlite3_js_vfs_create_file()*/) + }/*sqlite3_js_posix_create_file()*/) //////////////////////////////////////////////////////////////////// .t({ @@ -2605,28 +2605,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule; } } }/*kvvfs sanity checks*/) - .t({ - name: 'kvvfs sqlite3_js_vfs_create_file()', - predicate: ()=>"kvvfs does not currently support this", - test: function(sqlite3){ - let db; - try { - db = new this.JDb(this.kvvfsDbFile); - const exp = capi.sqlite3_js_db_export(db); - db.close(); - this.kvvfsUnlink(); - capi.sqlite3_js_vfs_create_file("kvvfs", this.kvvfsDbFile, exp); - db = new this.JDb(filename); - T.assert(6 === db.selectValue('select count(*) from kvvfs')); - }finally{ - db.close(); - this.kvvfsUnlink(); - } - delete this.kvvfsDbFile; - delete this.kvvfsUnlink; - delete this.JDb; - } - }/*kvvfs sqlite3_js_vfs_create_file()*/) ;/* end kvvfs tests */ //////////////////////////////////////////////////////////////////////// diff --git a/manifest b/manifest index 7fcaaf8277..5d7d990438 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JNI\sbuild\sfixes\sfor\splatforms\swhere\sthe\sjint\stype\sis\snot\sthe\ssame\sas\sint,\sas\sreported\sin\s[forum:9089d2049a|forum\spost\s9089d2049a]. -D 2023-11-08T12:56:23.623 +C Remove\san\sunused/invalid\stest\sfrom\sthe\swasm\ssuite. +D 2023-11-08T15:34:03.261 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -636,7 +636,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555 F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2 -F ext/wasm/tester1.c-pp.js d628826e936bd143d64e0fa3089752abeeeea38a34a7e2b18d364f090d4e99c6 +F ext/wasm/tester1.c-pp.js a92dc256738dbd1b50f142d1fd0c835294ba09b7bb6526650360e942f88cb63f F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2 @@ -2142,8 +2142,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 b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306 -R 3f46c0761970583c9dda3b5c30472d0c +P b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d +R 203d0511d76de1bd08375343f3ff1602 U stephan -Z b9bb3a53ca08337ab5c86e3c35fc1299 +Z 7f67038dd1c5d3f1db527f87a3f9a58b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d465a17824..97b3d8d6f8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d \ No newline at end of file +916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502 \ No newline at end of file From 0ad5301378dd567d86cfe5cc97774dc226968cfd Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 8 Nov 2023 15:49:57 +0000 Subject: [PATCH 30/55] Avoid blocking as part of passive checkpoint operations, even if SQLITE_ENABLE_SETLK_TIMEOUT is defined. FossilOrigin-Name: e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/wal.c | 7 ++++++- test/testrunner_data.tcl | 1 + 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 5d7d990438..a1dc817b0a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunused/invalid\stest\sfrom\sthe\swasm\ssuite. -D 2023-11-08T15:34:03.261 +C Avoid\sblocking\sas\spart\sof\spassive\scheckpoint\soperations,\seven\sif\sSQLITE_ENABLE_SETLK_TIMEOUT\sis\sdefined. +D 2023-11-08T15:49:57.172 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -806,7 +806,7 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8 F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7 F src/vtab.c 154725ebecd3bc02f7fbd7ad3974334f73fff76e02a964e828e48a7c5fb7efff F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 01e051a1e713d9eabdb25df38602837cec8f4c2cae448ce2cf6accc87af903e9 +F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/where.c 313ce81270d2a414672370e1ee74e65949ad620519193d4cac2986d073cbc8a0 @@ -1651,7 +1651,7 @@ F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc F test/tester.tcl 68454ef88508c196d19e8694daa27bff7107a91857799eaa12f417188ae53ede F test/testrunner.tcl 8a6721213bce1cfd3b33e1588cc6431143d96b98819206bf91f5a205fbb150d4 -F test/testrunner_data.tcl 7f73f93634d32dafc857ed491b840f371113d09fde6a8bfb9e47b938d47b8c85 +F test/testrunner_data.tcl e4d5017290a6d5c11785e36cc94c67d8bb950c8cdc2dbe4c1db2a3a583812560 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899 F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -2142,8 +2142,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 b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d -R 203d0511d76de1bd08375343f3ff1602 -U stephan -Z 7f67038dd1c5d3f1db527f87a3f9a58b +P 916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502 +R 5bea92ea8c9d0554fce6b86ad4fbcf31 +U dan +Z c817b07612729531bff15732a557a90b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 97b3d8d6f8..27f2be574e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502 \ No newline at end of file +e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index d63c13ffc4..655d78f591 100644 --- a/src/wal.c +++ b/src/wal.c @@ -4248,9 +4248,14 @@ int sqlite3WalCheckpoint( /* Read the wal-index header. */ SEH_TRY { if( rc==SQLITE_OK ){ + /* For a passive checkpoint, do not re-enable blocking locks after + ** reading the wal-index header. A passive checkpoint should not block + ** or invoke the busy handler. The only lock such a checkpoint may + ** attempt to obtain is a lock on a read-slot, and it should give up + ** immediately and do a partial checkpoint if it cannot obtain it. */ walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); - (void)walEnableBlocking(pWal); + if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } diff --git a/test/testrunner_data.tcl b/test/testrunner_data.tcl index 9032ced4dd..c4e24c4382 100644 --- a/test/testrunner_data.tcl +++ b/test/testrunner_data.tcl @@ -267,6 +267,7 @@ namespace eval trd { -DSQLITE_ENABLE_PERSIST_WAL=1 -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 -DSQLITE_ENABLE_RTREE=1 + -DSQLITE_ENABLE_SETLK_TIMEOUT=2 -DSQLITE_ENABLE_SNAPSHOT=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_MAX_LENGTH=2147483645 From e445586630bba75261a166d95bd27cd6063f390f Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 8 Nov 2023 15:51:42 +0000 Subject: [PATCH 31/55] Remove old files related to wapptest.tcl from test/ directory. FossilOrigin-Name: dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe --- manifest | 13 +- manifest.uuid | 2 +- test/releasetest_data.tcl | 846 -------------------------------- test/wapp.tcl | 987 -------------------------------------- test/wapptest.tcl | 909 ----------------------------------- 5 files changed, 6 insertions(+), 2751 deletions(-) delete mode 100644 test/releasetest_data.tcl delete mode 100644 test/wapp.tcl delete mode 100755 test/wapptest.tcl diff --git a/manifest b/manifest index a1dc817b0a..f8b0d56fd2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sblocking\sas\spart\sof\spassive\scheckpoint\soperations,\seven\sif\sSQLITE_ENABLE_SETLK_TIMEOUT\sis\sdefined. -D 2023-11-08T15:49:57.172 +C Remove\sold\sfiles\srelated\sto\swapptest.tcl\sfrom\stest/\sdirectory. +D 2023-11-08T15:51:42.810 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1487,7 +1487,6 @@ F test/recover.test fd5199f928757cb308661b5fdca1abc19398a798ff7f24b57c3071e9f8e0 F test/regexp1.test 8f2a8bc1569666e29a4cee6c1a666cd224eb6d50e2470d1dc1df995170f3e0f1 F test/regexp2.test 55ed41da802b0e284ac7e2fe944be3948f93ff25abbca0361a609acfed1368b5 F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d -F test/releasetest_data.tcl 50679c8de0e67ca93a47dc95fdf077ecbc4b6eceb14dcb76f19779ab44132e65 F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3 F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/returning1.test db532cde29d6aebbc48c6ddc3149b30476f8e69ca7a2c4b53986c7635e6fd8ec @@ -1952,8 +1951,6 @@ F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370 F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747 F test/walvfs.test e1a6ad0f3c78e98b55c3d5f0889cf366cc0d0a1cb2bccb44ac9ec67384adc4a1 -F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec -F test/wapptest.tcl 1bea58a6a8e68a73f542ee4fca28b771b84ed803bd0c9e385087070b3d747b3c x F test/where.test 59abb854eee24f166b5f7ba9d17eb250abc59ce0a66c48912ffb10763648196d F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6 F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753 @@ -2142,8 +2139,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 916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502 -R 5bea92ea8c9d0554fce6b86ad4fbcf31 +P e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572 +R ce83d55831eeaab82518466b14d3660d U dan -Z c817b07612729531bff15732a557a90b +Z aaf04791c4ef545a121de15f3eab560c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 27f2be574e..198e99f2b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572 \ No newline at end of file +dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe \ No newline at end of file diff --git a/test/releasetest_data.tcl b/test/releasetest_data.tcl deleted file mode 100644 index 95c1b7af19..0000000000 --- a/test/releasetest_data.tcl +++ /dev/null @@ -1,846 +0,0 @@ -# 2019 August 01 -# -# 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 implements a program that produces scripts (either shell scripts -# or batch files) to implement a particular test that is part of the SQLite -# release testing procedure. For example, to run veryquick.test with a -# specified set of -D compiler switches. -# -# A "configuration" is a set of options passed to [./configure] and [make] -# to build the SQLite library in a particular fashion. A "platform" is a -# list of tests; most platforms are named after the hardware/OS platform -# that the tests will be run on as part of the release procedure. Each -# "test" is a combination of a configuration and a makefile target (e.g. -# "fulltest"). The program may be invoked as follows: -# -set USAGE { -$argv0 script ?-msvc? CONFIGURATION TARGET - Given a configuration and make target, return a bash (or, if -msvc - is specified, batch) script to execute the test. The first argument - passed to the script must be a directory containing SQLite source code. - -$argv0 configurations - List available configurations. - -$argv0 platforms - List available platforms. - -$argv0 tests ?-nodebug? PLATFORM - List tests in a specified platform. If the -nodebug switch is - specified, synthetic debug/ndebug configurations are omitted. Each - test is a combination of a configuration and a makefile target. -} - -# Omit comments (text between # and \n) in a long multi-line string. -# -proc strip_comments {in} { - regsub -all {#[^\n]*\n} $in {} out - return $out -} - -array set ::Configs [strip_comments { - "Default" { - -O2 - --disable-amalgamation --disable-shared - --enable-session - -DSQLITE_ENABLE_RBU - } - "All-Debug" { - --enable-debug --enable-all - } - "All-O0" { - -O0 --enable-all - } - "Sanitize" { - CC=clang -fsanitize=address,undefined - -DSQLITE_ENABLE_STAT4 - -DCONFIG_SLOWDOWN_FACTOR=5.0 - --enable-debug - --enable-all - } - "Stdcall" { - -DUSE_STDCALL=1 - -O2 - } - "Have-Not" { - # The "Have-Not" configuration sets all possible -UHAVE_feature options - # in order to verify that the code works even on platforms that lack - # these support services. - -DHAVE_FDATASYNC=0 - -DHAVE_GMTIME_R=0 - -DHAVE_ISNAN=0 - -DHAVE_LOCALTIME_R=0 - -DHAVE_LOCALTIME_S=0 - -DHAVE_MALLOC_USABLE_SIZE=0 - -DHAVE_STRCHRNUL=0 - -DHAVE_USLEEP=0 - -DHAVE_UTIME=0 - } - "Unlock-Notify" { - -O2 - -DSQLITE_ENABLE_UNLOCK_NOTIFY - -DSQLITE_THREADSAFE - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 - } - "User-Auth" { - -O2 - -DSQLITE_USER_AUTHENTICATION=1 - } - "Secure-Delete" { - -O2 - -DSQLITE_SECURE_DELETE=1 - -DSQLITE_SOUNDEX=1 - } - "Update-Delete-Limit" { - -O2 - -DSQLITE_DEFAULT_FILE_FORMAT=4 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_ENABLE_STMT_SCANSTATUS - -DSQLITE_LIKE_DOESNT_MATCH_BLOBS - -DSQLITE_ENABLE_CURSOR_HINTS - } - "Check-Symbols" { - -DSQLITE_MEMDEBUG=1 - -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_MEMSYS5=1 - -DSQLITE_ENABLE_MEMSYS3=1 - -DSQLITE_ENABLE_COLUMN_METADATA=1 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_SECURE_DELETE=1 - -DSQLITE_SOUNDEX=1 - -DSQLITE_ENABLE_ATOMIC_WRITE=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_STMT_SCANSTATUS - --enable-fts5 --enable-session - } - "Debug-One" { - --disable-shared - -O2 -funsigned-char - -DSQLITE_DEBUG=1 - -DSQLITE_MEMDEBUG=1 - -DSQLITE_MUTEX_NOOP=1 - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_MEMSYS5=1 - -DSQLITE_ENABLE_COLUMN_METADATA=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DSQLITE_MAX_ATTACHED=125 - -DSQLITE_MUTATION_TEST - --enable-fts5 - } - "Debug-Two" { - -DSQLITE_DEFAULT_MEMSTATUS=0 - -DSQLITE_MAX_EXPR_DEPTH=0 - --enable-debug - } - "Fast-One" { - -O6 - -DSQLITE_ENABLE_FTS4=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_RBU - -DSQLITE_MAX_ATTACHED=125 - -DSQLITE_MAX_MMAP_SIZE=12884901888 - -DSQLITE_ENABLE_SORTER_MMAP=1 - -DLONGDOUBLE_TYPE=double - --enable-session - } - "Device-One" { - -O2 - -DSQLITE_DEBUG=1 - -DSQLITE_DEFAULT_AUTOVACUUM=1 - -DSQLITE_DEFAULT_CACHE_SIZE=64 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32 - -DSQLITE_DISABLE_LFS=1 - -DSQLITE_ENABLE_ATOMIC_WRITE=1 - -DSQLITE_ENABLE_IOTRACE=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_MAX_PAGE_SIZE=4096 - -DSQLITE_OMIT_LOAD_EXTENSION=1 - -DSQLITE_OMIT_PROGRESS_CALLBACK=1 - -DSQLITE_OMIT_VIRTUALTABLE=1 - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DSQLITE_TEMP_STORE=3 - } - "Device-Two" { - -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 - -DSQLITE_DEFAULT_AUTOVACUUM=1 - -DSQLITE_DEFAULT_CACHE_SIZE=1000 - -DSQLITE_DEFAULT_LOCKING_MODE=0 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 - -DSQLITE_DISABLE_LFS=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_MAX_COMPOUND_SELECT=50 - -DSQLITE_MAX_PAGE_SIZE=32768 - -DSQLITE_OMIT_TRACE=1 - -DSQLITE_TEMP_STORE=3 - -DSQLITE_THREADSAFE=2 - --enable-fts5 --enable-session - } - "Locking-Style" { - -O2 - -DSQLITE_ENABLE_LOCKING_STYLE=1 - } - "Apple" { - -Os - -DHAVE_GMTIME_R=1 - -DHAVE_ISNAN=1 - -DHAVE_LOCALTIME_R=1 - -DHAVE_PREAD=1 - -DHAVE_PWRITE=1 - -DHAVE_UTIME=1 - -DSQLITE_DEFAULT_CACHE_SIZE=1000 - -DSQLITE_DEFAULT_CKPTFULLFSYNC=1 - -DSQLITE_DEFAULT_MEMSTATUS=1 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1 - -DSQLITE_ENABLE_API_ARMOR=1 - -DSQLITE_ENABLE_AUTO_PROFILE=1 - -DSQLITE_ENABLE_FLOCKTIMEOUT=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 - -DSQLITE_ENABLE_FTS3_TOKENIZER=1 - -DSQLITE_ENABLE_PERSIST_WAL=1 - -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_SETLK_TIMEOUT=1 - -DSQLITE_ENABLE_SNAPSHOT=1 - # -DSQLITE_ENABLE_SQLLOG=1 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_MAX_LENGTH=2147483645 - -DSQLITE_MAX_VARIABLE_NUMBER=500000 - # -DSQLITE_MEMDEBUG=1 - -DSQLITE_NO_SYNC=1 - -DSQLITE_OMIT_AUTORESET=1 - -DSQLITE_OMIT_LOAD_EXTENSION=1 - -DSQLITE_PREFER_PROXY_LOCKING=1 - -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 - -DSQLITE_THREADSAFE=2 - -DSQLITE_USE_URI=1 - -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1 - -DUSE_GUARDED_FD=1 - -DUSE_PREAD=1 - --enable-fts5 - } - "Extra-Robustness" { - -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 - -DSQLITE_MAX_ATTACHED=62 - } - "Devkit" { - -DSQLITE_DEFAULT_FILE_FORMAT=4 - -DSQLITE_MAX_ATTACHED=30 - -DSQLITE_ENABLE_COLUMN_METADATA - -DSQLITE_ENABLE_FTS4 - -DSQLITE_ENABLE_FTS5 - -DSQLITE_ENABLE_FTS4_PARENTHESIS - -DSQLITE_DISABLE_FTS4_DEFERRED - -DSQLITE_ENABLE_RTREE - --enable-fts5 - } - "No-lookaside" { - -DSQLITE_TEST_REALLOC_STRESS=1 - -DSQLITE_OMIT_LOOKASIDE=1 - } - "Valgrind" { - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_FTS4 - -DSQLITE_ENABLE_RTREE - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DLONGDOUBLE_TYPE=double - -DCONFIG_SLOWDOWN_FACTOR=8.0 - } - - "Windows-Memdebug" { - MEMDEBUG=1 - DEBUG=3 - } - "Windows-Win32Heap" { - WIN32HEAP=1 - DEBUG=4 - } - - # The next group of configurations are used only by the - # Failure-Detection platform. They are all the same, but we need - # different names for them all so that they results appear in separate - # subdirectories. - # - Fail0 {-O0} - Fail2 {-O0} - Fail3 {-O0} - Fail4 {-O0} - FuzzFail1 {-O0} - FuzzFail2 {-O0} -}] -if {$tcl_platform(os)=="Darwin"} { - lappend Configs(Apple) -DSQLITE_ENABLE_LOCKING_STYLE=1 -} - -array set ::Platforms [strip_comments { - Linux-x86_64 { - "Check-Symbols*" "" checksymbols - "Fast-One" QUICKTEST_INCLUDE=rbu.test "fuzztest test" - "Debug-One" "" "mptest test" - "Debug-Two" "" test - "Have-Not" "" test - "Secure-Delete" "" test - "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test - "User-Auth" "" tcltest - "Update-Delete-Limit" "" test - "Extra-Robustness" "" test - "Device-Two" "" "threadtest test" - "No-lookaside" "" test - "Devkit" "" test - "Apple" "" test - "Sanitize*" "" test - "Device-One" "" alltest - "Default" "" "threadtest fuzztest alltest" - "Valgrind*" "" valgrindtest - } - Linux-i686 { - "Devkit" "" test - "Have-Not" "" test - "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test - "Device-One" "" test - "Device-Two" "" test - "Default" "" "threadtest fuzztest alltest" - } - Darwin-i386 { - "Locking-Style" "" "mptest test" - "Have-Not" "" test - "Apple" "" "threadtest fuzztest alltest" - } - Darwin-x86_64 { - "Locking-Style" "" "mptest test" - "Have-Not" "" test - "Apple" "" "threadtest fuzztest alltest" - } - Darwin-arm64 { - "Locking-Style" "" "mptest test" - "Have-Not" "" test - "Apple" "" "threadtest fuzztest alltest" - } - "Windows NT-intel" { - "Stdcall" "" test - "Have-Not" "" test - "Windows-Memdebug*" "" test - "Windows-Win32Heap*" "" test - "Default" "" "mptest fulltestonly" - } - "Windows NT-amd64" { - "Stdcall" "" test - "Have-Not" "" test - "Windows-Memdebug*" "" test - "Windows-Win32Heap*" "" test - "Default" "" "mptest fulltestonly" - } - - # The Failure-Detection platform runs various tests that deliberately - # fail. This is used as a test of this script to verify that this script - # correctly identifies failures. - # - Failure-Detection { - Fail0* "TEST_FAILURE=0" test - Sanitize* "TEST_FAILURE=1" test - Fail2* "TEST_FAILURE=2" valgrindtest - Fail3* "TEST_FAILURE=3" valgrindtest - Fail4* "TEST_FAILURE=4" test - FuzzFail1* "TEST_FAILURE=5" test - FuzzFail2* "TEST_FAILURE=5" valgrindtest - } -}] - -#-------------------------------------------------------------------------- -#-------------------------------------------------------------------------- -#-------------------------------------------------------------------------- -# End of configuration section. -#-------------------------------------------------------------------------- -#-------------------------------------------------------------------------- -#-------------------------------------------------------------------------- - -# Configuration verification: Check that each entry in the list of configs -# specified for each platforms exists. -# -foreach {key value} [array get ::Platforms] { - foreach {v vars t} $value { - if {[string range $v end end]=="*"} { - set v [string range $v 0 end-1] - } - if {0==[info exists ::Configs($v)]} { - puts stderr "No such configuration: \"$v\"" - exit -1 - } - } -} - -proc usage {} { - global argv0 - puts stderr [subst $::USAGE] - exit 1 -} - -proc is_prefix {p str min} { - set n [string length $p] - if {$n<$min} { return 0 } - if {[string range $str 0 [expr $n-1]]!=$p} { return 0 } - return 1 -} - -proc main_configurations {} { - foreach k [lsort [array names ::Configs]] { - puts $k - } -} - -proc main_platforms {} { - foreach k [lsort [array names ::Platforms]] { - puts "\"$k\"" - } -} - -proc main_script {args} { - set bMsvc 0 - set nArg [llength $args] - if {$nArg==3} { - if {![is_prefix [lindex $args 0] -msvc 2]} usage - set bMsvc 1 - } elseif {$nArg<2 || $nArg>3} { - usage - } - set config [lindex $args end-1] - set target [lindex $args end] - - set opts [list] ;# OPTS value - set cflags [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value - set makeOpts [list] ;# Extra args for [make] - set configOpts [list] ;# Extra args for [configure] - - if {$::tcl_platform(platform)=="windows" || $bMsvc} { - lappend opts -DSQLITE_OS_WIN=1 - } else { - lappend opts -DSQLITE_OS_UNIX=1 - } - - # Figure out if this is a synthetic ndebug or debug configuration. - # - set bRemoveDebug 0 - if {[string match *-ndebug $config]} { - set bRemoveDebug 1 - set config [string range $config 0 end-7] - } - if {[string match *-debug $config]} { - lappend opts -DSQLITE_DEBUG - lappend opts -DSQLITE_EXTRA_IFNULLROW - set config [string range $config 0 end-6] - } - regexp {^(.*)-[0-9]+} $config -> config - - # Ensure that the named configuration exists. - # - if {![info exists ::Configs($config)]} { - puts stderr "No such config: $config" - exit 1 - } - - # Loop through the parameters of the nominated configuration, updating - # $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as - # follows: - # - # 1. If the parameter begins with a "*", discard it. - # - # 2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or - # -DSQLITE_DEBUG=1, discard it - # - # 3. If the parameter begins with "-D", add it to $opts. - # - # 4. If the parameter begins with "--" add it to $configOpts. Unless - # this command is preparing a script for MSVC - then add an - # equivalent to $makeOpts or $opts. - # - # 5. If the parameter begins with "-" add it to $cflags. If in MSVC - # mode and the parameter is an -O option, instead add - # an OPTIMIZATIONS= switch to $makeOpts. - # - # 6. If none of the above apply, add the parameter to $makeOpts - # - foreach param $::Configs($config) { - if {[string range $param 0 0]=="*"} continue - - if {$bRemoveDebug} { - if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1" - || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1" - || $param=="--enable-debug" - } { - continue - } - } - - if {[string range $param 0 1]=="-D"} { - lappend opts $param - continue - } - - if {[string range $param 0 1]=="--"} { - if {$bMsvc} { - switch -- $param { - --disable-amalgamation { - lappend makeOpts USE_AMALGAMATION=0 - } - --disable-shared { - lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 - } - --enable-fts5 { - lappend opts -DSQLITE_ENABLE_FTS5 - } - --enable-shared { - lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 - } - --enable-session { - lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK - lappend opts -DSQLITE_ENABLE_SESSION - } - default { - error "Cannot translate $param for MSVC" - } - } - } else { - lappend configOpts $param - } - - continue - } - - if {[string range $param 0 0]=="-"} { - if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} { - lappend makeOpts OPTIMIZATIONS=$level - } else { - lappend cflags $param - } - continue - } - - lappend makeOpts $param - } - - # Some configurations specify -DHAVE_USLEEP=0. For all others, add - # -DHAVE_USLEEP=1. - # - if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} { - lappend opts -DHAVE_USLEEP=1 - } - - if {$bMsvc==0} { - puts {set -e} - puts {} - puts {if [ "$#" -ne 1 ] ; then} - puts { echo "Usage: $0 " } - puts { exit -1 } - puts {fi } - puts {SRCDIR=$1} - puts {} - puts "TCL=\"[::tcl::pkgconfig get libdir,install]\"" - - puts "\$SRCDIR/configure --with-tcl=\$TCL $configOpts" - puts {} - puts {OPTS=" -DSQLITE_NO_SYNC=1"} - foreach o $opts { - puts "OPTS=\"\$OPTS $o\"" - } - puts {} - puts "CFLAGS=\"$cflags\"" - puts {} - puts "make $target \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts" - } else { - - puts {set SRCDIR=%1} - set makecmd "nmake /f %SRCDIR%\\Makefile.msc TOP=%SRCDIR% $target " - append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts" - - puts "set TMP=%CD%" - puts $makecmd - } -} - -proc main_trscript {args} { - set bMsvc 0 - set nArg [llength $args] - if {$nArg==3} { - if {![is_prefix [lindex $args 0] -msvc 2]} usage - set bMsvc 1 - } elseif {$nArg<2 || $nArg>3} { - usage - } - set config [lindex $args end-1] - set srcdir [lindex $args end] - - set opts [list] ;# OPTS value - set cflags [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value - set makeOpts [list] ;# Extra args for [make] - set configOpts [list] ;# Extra args for [configure] - - if {$::tcl_platform(platform)=="windows" || $bMsvc} { - lappend opts -DSQLITE_OS_WIN=1 - } else { - lappend opts -DSQLITE_OS_UNIX=1 - } - - # Figure out if this is a synthetic ndebug or debug configuration. - # - set bRemoveDebug 0 - if {[string match *-ndebug $config]} { - set bRemoveDebug 1 - set config [string range $config 0 end-7] - } - if {[string match *-debug $config]} { - lappend opts -DSQLITE_DEBUG - lappend opts -DSQLITE_EXTRA_IFNULLROW - set config [string range $config 0 end-6] - } - regexp {^(.*)-[0-9]+} $config -> config - - # Ensure that the named configuration exists. - # - if {![info exists ::Configs($config)]} { - puts stderr "No such config: $config" - exit 1 - } - - # Loop through the parameters of the nominated configuration, updating - # $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as - # follows: - # - # 1. If the parameter begins with a "*", discard it. - # - # 2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or - # -DSQLITE_DEBUG=1, discard it - # - # 3. If the parameter begins with "-D", add it to $opts. - # - # 4. If the parameter begins with "--" add it to $configOpts. Unless - # this command is preparing a script for MSVC - then add an - # equivalent to $makeOpts or $opts. - # - # 5. If the parameter begins with "-" add it to $cflags. If in MSVC - # mode and the parameter is an -O option, instead add - # an OPTIMIZATIONS= switch to $makeOpts. - # - # 6. If none of the above apply, add the parameter to $makeOpts - # - foreach param $::Configs($config) { - if {[string range $param 0 0]=="*"} continue - - if {$bRemoveDebug} { - if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1" - || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1" - || $param=="--enable-debug" - } { - continue - } - } - - if {[string range $param 0 1]=="-D"} { - lappend opts $param - continue - } - - if {[string range $param 0 1]=="--"} { - if {$bMsvc} { - switch -- $param { - --disable-amalgamation { - lappend makeOpts USE_AMALGAMATION=0 - } - --disable-shared { - lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 - } - --enable-fts5 { - lappend opts -DSQLITE_ENABLE_FTS5 - } - --enable-shared { - lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 - } - --enable-session { - lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK - lappend opts -DSQLITE_ENABLE_SESSION - } - --enable-all { - } - --enable-debug { - # lappend makeOpts OPTIMIZATIONS=0 - lappend opts -DSQLITE_DEBUG - } - default { - error "Cannot translate $param for MSVC" - } - } - } else { - lappend configOpts $param - } - - continue - } - - if {[string range $param 0 0]=="-"} { - if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} { - lappend makeOpts OPTIMIZATIONS=$level - } else { - lappend cflags $param - } - continue - } - - lappend makeOpts $param - } - - # Some configurations specify -DHAVE_USLEEP=0. For all others, add - # -DHAVE_USLEEP=1. - # - if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} { - lappend opts -DHAVE_USLEEP=1 - } - - if {$bMsvc==0} { - puts {set -e} - puts {} - puts {if [ "$#" -ne 1 ] ; then} - puts { echo "Usage: $0 " } - puts { exit -1 } - puts {fi } - puts "SRCDIR=\"$srcdir\"" - puts {} - puts "TCL=\"[::tcl::pkgconfig get libdir,install]\"" - - puts {if [ ! -f Makefile ] ; then} - puts " \$SRCDIR/configure --with-tcl=\$TCL $configOpts" - puts {fi} - puts {} - if {[info exists ::env(OPTS)]} { - puts "# From environment variable:" - puts "OPTS=$::env(OPTS)" - puts "" - } - puts {OPTS="$OPTS -DSQLITE_NO_SYNC=1"} - foreach o $opts { - puts "OPTS=\"\$OPTS $o\"" - } - puts {} - puts "CFLAGS=\"$cflags\"" - puts {} - puts "make \$1 \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts" - } else { - - set srcdir [file nativename [file normalize $srcdir]] - # set srcdir [string map [list "\\" "\\\\"] $srcdir] - - puts {set TARGET=%1} - set makecmd "nmake /f $srcdir\\Makefile.msc TOP=\"$srcdir\" %TARGET% " - append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts" - - puts "set TMP=%CD%" - puts $makecmd - } -} - -proc main_tests {args} { - set bNodebug 0 - set nArg [llength $args] - if {$nArg==2} { - if {[is_prefix [lindex $args 0] -nodebug 2]} { - set bNodebug 1 - } elseif {[is_prefix [lindex $args 0] -debug 2]} { - set bNodebug 0 - } else usage - } elseif {$nArg==0 || $nArg>2} { - usage - } - set p [lindex $args end] - if {![info exists ::Platforms($p)]} { - puts stderr "No such platform: $p" - exit 1 - } - - set lTest [list] - - foreach {config vars target} $::Platforms($p) { - if {[string range $config end end]=="*"} { - set config [string range $config 0 end-1] - } elseif {$bNodebug==0} { - set dtarget test - if {[lsearch $target fuzztest]<0 && [lsearch $target test]<0} { - set dtarget tcltest - } - if {$vars!=""} { set dtarget "$vars $dtarget" } - - if {[string first SQLITE_DEBUG $::Configs($config)]>=0 - || [string first --enable-debug $::Configs($config)]>=0 - } { - lappend lTest "$config-ndebug \"$dtarget\"" - } else { - lappend lTest "$config-debug \"$dtarget\"" - } - } - - if {[llength $target]==1 && ([string match "*TEST_FAILURE*" $vars] || ( - [lsearch $target "valgrindtest"]<0 - && [lsearch $target "alltest"]<0 - && [lsearch $target "fulltestonly"]<0 - && ![string match Sanitize* $config] - ))} { - if {$vars!=""} { set target "$vars $target" } - lappend lTest "$config \"$target\"" - } else { - set idir -1 - foreach t $target { - if {$t=="valgrindtest" || $t=="alltest" || $t=="fulltestonly" - || [string match Sanitize* $config] - } { - if {$vars!=""} { set t "$vars $t" } - for {set ii 1} {$ii<=4} {incr ii} { - lappend lTest "$config-[incr idir] \"TCLTEST_PART=$ii/4 $t\"" - } - } else { - if {$vars!=""} { set t "$vars $t" } - lappend lTest "$config-[incr idir] \"$t\"" - } - } - } - } - - foreach l $lTest { - puts $l - } - -} - -if {[llength $argv]==0} { usage } -set cmd [lindex $argv 0] -set n [expr [llength $argv]-1] -if {[string match ${cmd}* configurations] && $n==0} { - main_configurations -} elseif {[string match ${cmd}* script]} { - main_script {*}[lrange $argv 1 end] -} elseif {[string match ${cmd}* trscript]} { - main_trscript {*}[lrange $argv 1 end] -} elseif {[string match ${cmd}* platforms] && $n==0} { - main_platforms -} elseif {[string match ${cmd}* tests]} { - main_tests {*}[lrange $argv 1 end] -} else { - usage -} diff --git a/test/wapp.tcl b/test/wapp.tcl deleted file mode 100644 index 53c21e892f..0000000000 --- a/test/wapp.tcl +++ /dev/null @@ -1,987 +0,0 @@ -# Copyright (c) 2017 D. Richard Hipp -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the Simplified BSD License (also -# known as the "2-Clause License" or "FreeBSD License".) -# -# This program is distributed in the hope that it will be useful, -# but without any warranty; without even the implied warranty of -# merchantability or fitness for a particular purpose. -# -#--------------------------------------------------------------------------- -# -# Design rules: -# -# (1) All identifiers in the global namespace begin with "wapp" -# -# (2) Indentifiers intended for internal use only begin with "wappInt" -# -package require Tcl 8.6 - -# Add text to the end of the HTTP reply. No interpretation or transformation -# of the text is performs. The argument should be enclosed within {...} -# -proc wapp {txt} { - global wapp - dict append wapp .reply $txt -} - -# Add text to the page under construction. Do no escaping on the text. -# -# Though "unsafe" in general, there are uses for this kind of thing. -# For example, if you want to return the complete, unmodified content of -# a file: -# -# set fd [open content.html rb] -# wapp-unsafe [read $fd] -# close $fd -# -# You could do the same thing using ordinary "wapp" instead of "wapp-unsafe". -# The difference is that wapp-safety-check will complain about the misuse -# of "wapp", but it assumes that the person who write "wapp-unsafe" understands -# the risks. -# -# Though occasionally necessary, the use of this interface should be minimized. -# -proc wapp-unsafe {txt} { - global wapp - dict append wapp .reply $txt -} - -# Add text to the end of the reply under construction. The following -# substitutions are made: -# -# %html(...) Escape text for inclusion in HTML -# %url(...) Escape text for use as a URL -# %qp(...) Escape text for use as a URI query parameter -# %string(...) Escape text for use within a JSON string -# %unsafe(...) No transformations of the text -# -# The substitutions above terminate at the first ")" character. If the -# text of the TCL string in ... contains ")" characters itself, use instead: -# -# %html%(...)% -# %url%(...)% -# %qp%(...)% -# %string%(...)% -# %unsafe%(...)% -# -# In other words, use "%(...)%" instead of "(...)" to include the TCL string -# to substitute. -# -# The %unsafe substitution should be avoided whenever possible, obviously. -# In addition to the substitutions above, the text also does backslash -# escapes. -# -# The wapp-trim proc works the same as wapp-subst except that it also removes -# whitespace from the left margin, so that the generated HTML/CSS/Javascript -# does not appear to be indented when delivered to the client web browser. -# -if {$tcl_version>=8.7} { - proc wapp-subst {txt} { - global wapp - regsub -all -command \ - {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt - dict append wapp .reply [subst -novariables -nocommand $txt] - } - proc wapp-trim {txt} { - global wapp - regsub -all {\n\s+} [string trim $txt] \n txt - regsub -all -command \ - {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt - dict append wapp .reply [subst -novariables -nocommand $txt] - } - proc wappInt-enc {all mode nu1 txt} { - return [uplevel 2 "wappInt-enc-$mode \"$txt\""] - } -} else { - proc wapp-subst {txt} { - global wapp - regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \ - {[wappInt-enc-\1 "\3"]} txt - dict append wapp .reply [uplevel 1 [list subst -novariables $txt]] - } - proc wapp-trim {txt} { - global wapp - regsub -all {\n\s+} [string trim $txt] \n txt - regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \ - {[wappInt-enc-\1 "\3"]} txt - dict append wapp .reply [uplevel 1 [list subst -novariables $txt]] - } -} - -# There must be a wappInt-enc-NAME routine for each possible substitution -# in wapp-subst. Thus there are routines for "html", "url", "qp", and "unsafe". -# -# wappInt-enc-html Escape text so that it is safe to use in the -# body of an HTML document. -# -# wappInt-enc-url Escape text so that it is safe to pass as an -# argument to href= and src= attributes in HTML. -# -# wappInt-enc-qp Escape text so that it is safe to use as the -# value of a query parameter in a URL or in -# post data or in a cookie. -# -# wappInt-enc-string Escape ", ', \, and < for using inside of a -# javascript string literal. The < character -# is escaped to prevent "" from causing -# problems in embedded javascript. -# -# wappInt-enc-unsafe Perform no encoding at all. Unsafe. -# -proc wappInt-enc-html {txt} { - return [string map {& & < < > > \" " \\ \} $txt] -} -proc wappInt-enc-unsafe {txt} { - return $txt -} -proc wappInt-enc-url {s} { - if {[regsub -all {[^-{}@~?=#_.:/a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} { - set s [subst -novar -noback $s] - } - if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} { - set s [subst -novar -noback $s] - } - return $s -} -proc wappInt-enc-qp {s} { - if {[regsub -all {[^-{}_.a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} { - set s [subst -novar -noback $s] - } - if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} { - set s [subst -novar -noback $s] - } - return $s -} -proc wappInt-enc-string {s} { - return [string map {\\ \\\\ \" \\\" ' \\' < \\u003c} $s] -} - -# This is a helper routine for wappInt-enc-url and wappInt-enc-qp. It returns -# an appropriate %HH encoding for the single character c. If c is a unicode -# character, then this routine might return multiple bytes: %HH%HH%HH -# -proc wappInt-%HHchar {c} { - if {$c==" "} {return +} - return [regsub -all .. [binary encode hex [encoding convertto utf-8 $c]] {%&}] -} - - -# Undo the www-url-encoded format. -# -# HT: This code stolen from ncgi.tcl -# -proc wappInt-decode-url {str} { - set str [string map [list + { } "\\" "\\\\" \[ \\\[ \] \\\]] $str] - regsub -all -- \ - {%([Ee][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \ - $str {[encoding convertfrom utf-8 [binary decode hex \1\2\3]]} str - regsub -all -- \ - {%([CDcd][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \ - $str {[encoding convertfrom utf-8 [binary decode hex \1\2]]} str - regsub -all -- {%([0-7][A-Fa-f0-9])} $str {\\u00\1} str - return [subst -novar $str] -} - -# Reset the document back to an empty string. -# -proc wapp-reset {} { - global wapp - dict set wapp .reply {} -} - -# Change the mime-type of the result document. -# -proc wapp-mimetype {x} { - global wapp - dict set wapp .mimetype $x -} - -# Change the reply code. -# -proc wapp-reply-code {x} { - global wapp - dict set wapp .reply-code $x -} - -# Set a cookie -# -proc wapp-set-cookie {name value} { - global wapp - dict lappend wapp .new-cookies $name $value -} - -# Unset a cookie -# -proc wapp-clear-cookie {name} { - wapp-set-cookie $name {} -} - -# Add extra entries to the reply header -# -proc wapp-reply-extra {name value} { - global wapp - dict lappend wapp .reply-extra $name $value -} - -# Specifies how the web-page under construction should be cached. -# The argument should be one of: -# -# no-cache -# max-age=N (for some integer number of seconds, N) -# private,max-age=N -# -proc wapp-cache-control {x} { - wapp-reply-extra Cache-Control $x -} - -# Redirect to a different web page -# -proc wapp-redirect {uri} { - wapp-reply-code {307 Redirect} - wapp-reply-extra Location $uri -} - -# Return the value of a wapp parameter -# -proc wapp-param {name {dflt {}}} { - global wapp - if {![dict exists $wapp $name]} {return $dflt} - return [dict get $wapp $name] -} - -# Return true if a and only if the wapp parameter $name exists -# -proc wapp-param-exists {name} { - global wapp - return [dict exists $wapp $name] -} - -# Set the value of a wapp parameter -# -proc wapp-set-param {name value} { - global wapp - dict set wapp $name $value -} - -# Return all parameter names that match the GLOB pattern, or all -# names if the GLOB pattern is omitted. -# -proc wapp-param-list {{glob {*}}} { - global wapp - return [dict keys $wapp $glob] -} - -# By default, Wapp does not decode query parameters and POST parameters -# for cross-origin requests. This is a security restriction, designed to -# help prevent cross-site request forgery (CSRF) attacks. -# -# As a consequence of this restriction, URLs for sites generated by Wapp -# that contain query parameters will not work as URLs found in other -# websites. You cannot create a link from a second website into a Wapp -# website if the link contains query planner, by default. -# -# Of course, it is sometimes desirable to allow query parameters on external -# links. For URLs for which this is safe, the application should invoke -# wapp-allow-xorigin-params. This procedure tells Wapp that it is safe to -# go ahead and decode the query parameters even for cross-site requests. -# -# In other words, for Wapp security is the default setting. Individual pages -# need to actively disable the cross-site request security if those pages -# are safe for cross-site access. -# -proc wapp-allow-xorigin-params {} { - global wapp - if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} { - wappInt-decode-query-params - } -} - -# Set the content-security-policy. -# -# The default content-security-policy is very strict: "default-src 'self'" -# The default policy prohibits the use of in-line javascript or CSS. -# -# Provide an alternative CSP as the argument. Or use "off" to disable -# the CSP completely. -# -proc wapp-content-security-policy {val} { - global wapp - if {$val=="off"} { - dict unset wapp .csp - } else { - dict set wapp .csp $val - } -} - -# Examine the bodys of all procedures in this program looking for -# unsafe calls to various Wapp interfaces. Return a text string -# containing warnings. Return an empty string if all is ok. -# -# This routine is advisory only. It misses some constructs that are -# dangerous and flags others that are safe. -# -proc wapp-safety-check {} { - set res {} - foreach p [info procs] { - set ln 0 - foreach x [split [info body $p] \n] { - incr ln - if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail] - && [string index $tail 0]!="\173" - && [regexp {[[$]} $tail] - } { - append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n" - } - if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} { - append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n" - } - } - } - return $res -} - -# Return a string that descripts the current environment. Applications -# might find this useful for debugging. -# -proc wapp-debug-env {} { - global wapp - set out {} - foreach var [lsort [dict keys $wapp]] { - if {[string index $var 0]=="."} continue - append out "$var = [list [dict get $wapp $var]]\n" - } - append out "\[pwd\] = [list [pwd]]\n" - return $out -} - -# Tracing function for each HTTP request. This is overridden by wapp-start -# if tracing is enabled. -# -proc wappInt-trace {} {} - -# Start up a listening socket. Arrange to invoke wappInt-new-connection -# for each inbound HTTP connection. -# -# port Listen on this TCP port. 0 means to select a port -# that is not currently in use -# -# wappmode One of "scgi", "remote-scgi", "server", or "local". -# -# fromip If not {}, then reject all requests from IP addresses -# other than $fromip -# -proc wappInt-start-listener {port wappmode fromip} { - if {[string match *scgi $wappmode]} { - set type SCGI - set server [list wappInt-new-connection \ - wappInt-scgi-readable $wappmode $fromip] - } else { - set type HTTP - set server [list wappInt-new-connection \ - wappInt-http-readable $wappmode $fromip] - } - if {$wappmode=="local" || $wappmode=="scgi"} { - set x [socket -server $server -myaddr 127.0.0.1 $port] - } else { - set x [socket -server $server $port] - } - set coninfo [chan configure $x -sockname] - set port [lindex $coninfo 2] - if {$wappmode=="local"} { - wappInt-start-browser http://127.0.0.1:$port/ - } elseif {$fromip!=""} { - puts "Listening for $type requests on TCP port $port from IP $fromip" - } else { - puts "Listening for $type requests on TCP port $port" - } -} - -# Start a web-browser and point it at $URL -# -proc wappInt-start-browser {url} { - global tcl_platform - if {$tcl_platform(platform)=="windows"} { - exec cmd /c start $url & - } elseif {$tcl_platform(os)=="Darwin"} { - exec open $url & - } elseif {[catch {exec xdg-open $url}]} { - exec firefox $url & - } -} - -# This routine is a "socket -server" callback. The $chan, $ip, and $port -# arguments are added by the socket command. -# -# Arrange to invoke $callback when content is available on the new socket. -# The $callback will process inbound HTTP or SCGI content. Reject the -# request if $fromip is not an empty string and does not match $ip. -# -proc wappInt-new-connection {callback wappmode fromip chan ip port} { - upvar #0 wappInt-$chan W - if {$fromip!="" && ![string match $fromip $ip]} { - close $chan - return - } - set W [dict create REMOTE_ADDR $ip REMOTE_PORT $port WAPP_MODE $wappmode \ - .header {}] - fconfigure $chan -blocking 0 -translation binary - fileevent $chan readable [list $callback $chan] -} - -# Close an input channel -# -proc wappInt-close-channel {chan} { - if {$chan=="stdout"} { - # This happens after completing a CGI request - exit 0 - } else { - unset ::wappInt-$chan - close $chan - } -} - -# Process new text received on an inbound HTTP request -# -proc wappInt-http-readable {chan} { - if {[catch [list wappInt-http-readable-unsafe $chan] msg]} { - puts stderr "$msg\n$::errorInfo" - wappInt-close-channel $chan - } -} -proc wappInt-http-readable-unsafe {chan} { - upvar #0 wappInt-$chan W wapp wapp - if {![dict exists $W .toread]} { - # If the .toread key is not set, that means we are still reading - # the header - set line [string trimright [gets $chan]] - set n [string length $line] - if {$n>0} { - if {[dict get $W .header]=="" || [regexp {^\s+} $line]} { - dict append W .header $line - } else { - dict append W .header \n$line - } - if {[string length [dict get $W .header]]>100000} { - error "HTTP request header too big - possible DOS attack" - } - } elseif {$n==0} { - # We have reached the blank line that terminates the header. - global argv0 - set a0 [file normalize $argv0] - dict set W SCRIPT_FILENAME $a0 - dict set W DOCUMENT_ROOT [file dir $a0] - if {[wappInt-parse-header $chan]} { - catch {close $chan} - return - } - set len 0 - if {[dict exists $W CONTENT_LENGTH]} { - set len [dict get $W CONTENT_LENGTH] - } - if {$len>0} { - # Still need to read the query content - dict set W .toread $len - } else { - # There is no query content, so handle the request immediately - set wapp $W - wappInt-handle-request $chan 0 - } - } - } else { - # If .toread is set, that means we are reading the query content. - # Continue reading until .toread reaches zero. - set got [read $chan [dict get $W .toread]] - dict append W CONTENT $got - dict set W .toread [expr {[dict get $W .toread]-[string length $got]}] - if {[dict get $W .toread]<=0} { - # Handle the request as soon as all the query content is received - set wapp $W - wappInt-handle-request $chan 0 - } - } -} - -# Decode the HTTP request header. -# -# This routine is always running inside of a [catch], so if -# any problems arise, simply raise an error. -# -proc wappInt-parse-header {chan} { - upvar #0 wappInt-$chan W - set hdr [split [dict get $W .header] \n] - if {$hdr==""} {return 1} - set req [lindex $hdr 0] - dict set W REQUEST_METHOD [set method [lindex $req 0]] - if {[lsearch {GET HEAD POST} $method]<0} { - error "unsupported request method: \"[dict get $W REQUEST_METHOD]\"" - } - set uri [lindex $req 1] - set split_uri [split $uri ?] - set uri0 [lindex $split_uri 0] - if {![regexp {^/[-.a-z0-9_/]*$} $uri0]} { - error "invalid request uri: \"$uri0\"" - } - dict set W REQUEST_URI $uri0 - dict set W PATH_INFO $uri0 - set uri1 [lindex $split_uri 1] - dict set W QUERY_STRING $uri1 - set n [llength $hdr] - for {set i 1} {$i<$n} {incr i} { - set x [lindex $hdr $i] - if {![regexp {^(.+): +(.*)$} $x all name value]} { - error "invalid header line: \"$x\"" - } - set name [string toupper $name] - switch -- $name { - REFERER {set name HTTP_REFERER} - USER-AGENT {set name HTTP_USER_AGENT} - CONTENT-LENGTH {set name CONTENT_LENGTH} - CONTENT-TYPE {set name CONTENT_TYPE} - HOST {set name HTTP_HOST} - COOKIE {set name HTTP_COOKIE} - ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING} - default {set name .hdr:$name} - } - dict set W $name $value - } - return 0 -} - -# Decode the QUERY_STRING parameters from a GET request or the -# application/x-www-form-urlencoded CONTENT from a POST request. -# -# This routine sets the ".qp" element of the ::wapp dict as a signal -# that query parameters have already been decoded. -# -proc wappInt-decode-query-params {} { - global wapp - dict set wapp .qp 1 - if {[dict exists $wapp QUERY_STRING]} { - foreach qterm [split [dict get $wapp QUERY_STRING] &] { - set qsplit [split $qterm =] - set nm [lindex $qsplit 0] - if {[regexp {^[a-z][a-z0-9]*$} $nm]} { - dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] - } - } - } - if {[dict exists $wapp CONTENT_TYPE] && [dict exists $wapp CONTENT]} { - set ctype [dict get $wapp CONTENT_TYPE] - if {$ctype=="application/x-www-form-urlencoded"} { - foreach qterm [split [string trim [dict get $wapp CONTENT]] &] { - set qsplit [split $qterm =] - set nm [lindex $qsplit 0] - if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { - dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] - } - } - } elseif {[string match multipart/form-data* $ctype]} { - regexp {^(.*?)\r\n(.*)$} [dict get $wapp CONTENT] all divider body - set ndiv [string length $divider] - while {[string length $body]} { - set idx [string first $divider $body] - set unit [string range $body 0 [expr {$idx-3}]] - set body [string range $body [expr {$idx+$ndiv+2}] end] - if {[regexp {^Content-Disposition: form-data; (.*?)\r\n\r\n(.*)$} \ - $unit unit hdr content]} { - if {[regexp {name="(.*)"; filename="(.*)"\r\nContent-Type: (.*?)$}\ - $hdr hr name filename mimetype]} { - dict set wapp $name.filename \ - [string map [list \\\" \" \\\\ \\] $filename] - dict set wapp $name.mimetype $mimetype - dict set wapp $name.content $content - } elseif {[regexp {name="(.*)"} $hdr hr name]} { - dict set wapp $name $content - } - } - } - } - } -} - -# Invoke application-supplied methods to generate a reply to -# a single HTTP request. -# -# This routine always runs within [catch], so handle exceptions by -# invoking [error]. -# -proc wappInt-handle-request {chan useCgi} { - global wapp - dict set wapp .reply {} - dict set wapp .mimetype {text/html; charset=utf-8} - dict set wapp .reply-code {200 Ok} - dict set wapp .csp {default-src 'self'} - - # Set up additional CGI environment values - # - if {![dict exists $wapp HTTP_HOST]} { - dict set wapp BASE_URL {} - } elseif {[dict exists $wapp HTTPS]} { - dict set wapp BASE_URL https://[dict get $wapp HTTP_HOST] - } else { - dict set wapp BASE_URL http://[dict get $wapp HTTP_HOST] - } - if {![dict exists $wapp REQUEST_URI]} { - dict set wapp REQUEST_URI / - } elseif {[regsub {\?.*} [dict get $wapp REQUEST_URI] {} newR]} { - # Some servers (ex: nginx) append the query parameters to REQUEST_URI. - # These need to be stripped off - dict set wapp REQUEST_URI $newR - } - if {[dict exists $wapp SCRIPT_NAME]} { - dict append wapp BASE_URL [dict get $wapp SCRIPT_NAME] - } else { - dict set wapp SCRIPT_NAME {} - } - if {![dict exists $wapp PATH_INFO]} { - # If PATH_INFO is missing (ex: nginx) then construct it - set URI [dict get $wapp REQUEST_URI] - set skip [string length [dict get $wapp SCRIPT_NAME]] - dict set wapp PATH_INFO [string range $URI $skip end] - } - if {[regexp {^/([^/]+)(.*)$} [dict get $wapp PATH_INFO] all head tail]} { - dict set wapp PATH_HEAD $head - dict set wapp PATH_TAIL [string trimleft $tail /] - } else { - dict set wapp PATH_INFO {} - dict set wapp PATH_HEAD {} - dict set wapp PATH_TAIL {} - } - dict set wapp SELF_URL [dict get $wapp BASE_URL]/[dict get $wapp PATH_HEAD] - - # Parse query parameters from the query string, the cookies, and - # POST data - # - if {[dict exists $wapp HTTP_COOKIE]} { - foreach qterm [split [dict get $wapp HTTP_COOKIE] {;}] { - set qsplit [split [string trim $qterm] =] - set nm [lindex $qsplit 0] - if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { - dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] - } - } - } - set same_origin 0 - if {[dict exists $wapp HTTP_REFERER]} { - set referer [dict get $wapp HTTP_REFERER] - set base [dict get $wapp BASE_URL] - if {$referer==$base || [string match $base/* $referer]} { - set same_origin 1 - } - } - dict set wapp SAME_ORIGIN $same_origin - if {$same_origin} { - wappInt-decode-query-params - } - - # Invoke the application-defined handler procedure for this page - # request. If an error occurs while running that procedure, generate - # an HTTP reply that contains the error message. - # - wapp-before-dispatch-hook - wappInt-trace - set mname [dict get $wapp PATH_HEAD] - if {[catch { - if {$mname!="" && [llength [info proc wapp-page-$mname]]>0} { - wapp-page-$mname - } else { - wapp-default - } - } msg]} { - if {[wapp-param WAPP_MODE]=="local" || [wapp-param WAPP_MODE]=="server"} { - puts "ERROR: $::errorInfo" - } - wapp-reset - wapp-reply-code "500 Internal Server Error" - wapp-mimetype text/html - wapp-trim { -

    Wapp Application Error

    -
    %html($::errorInfo)
    - } - dict unset wapp .new-cookies - } - - # Transmit the HTTP reply - # - if {$chan=="stdout"} { - puts $chan "Status: [dict get $wapp .reply-code]\r" - } else { - puts $chan "HTTP/1.1 [dict get $wapp .reply-code]\r" - puts $chan "Server: wapp\r" - puts $chan "Connection: close\r" - } - if {[dict exists $wapp .reply-extra]} { - foreach {name value} [dict get $wapp .reply-extra] { - puts $chan "$name: $value\r" - } - } - if {[dict exists $wapp .csp]} { - puts $chan "Content-Security-Policy: [dict get $wapp .csp]\r" - } - set mimetype [dict get $wapp .mimetype] - puts $chan "Content-Type: $mimetype\r" - if {[dict exists $wapp .new-cookies]} { - foreach {nm val} [dict get $wapp .new-cookies] { - if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { - if {$val==""} { - puts $chan "Set-Cookie: $nm=; HttpOnly; Path=/; Max-Age=1\r" - } else { - set val [wappInt-enc-url $val] - puts $chan "Set-Cookie: $nm=$val; HttpOnly; Path=/\r" - } - } - } - } - if {[string match text/* $mimetype]} { - set reply [encoding convertto utf-8 [dict get $wapp .reply]] - if {[regexp {\ygzip\y} [wapp-param HTTP_ACCEPT_ENCODING]]} { - catch { - set x [zlib gzip $reply] - set reply $x - puts $chan "Content-Encoding: gzip\r" - } - } - } else { - set reply [dict get $wapp .reply] - } - puts $chan "Content-Length: [string length $reply]\r" - puts $chan \r - puts -nonewline $chan $reply - flush $chan - wappInt-close-channel $chan -} - -# This routine runs just prior to request-handler dispatch. The -# default implementation is a no-op, but applications can override -# to do additional transformations or checks. -# -proc wapp-before-dispatch-hook {} {return} - -# Process a single CGI request -# -proc wappInt-handle-cgi-request {} { - global wapp env - foreach key { - CONTENT_LENGTH - CONTENT_TYPE - DOCUMENT_ROOT - HTTP_ACCEPT_ENCODING - HTTP_COOKIE - HTTP_HOST - HTTP_REFERER - HTTP_USER_AGENT - HTTPS - PATH_INFO - QUERY_STRING - REMOTE_ADDR - REQUEST_METHOD - REQUEST_URI - REMOTE_USER - SCRIPT_FILENAME - SCRIPT_NAME - SERVER_NAME - SERVER_PORT - SERVER_PROTOCOL - } { - if {[info exists env($key)]} { - dict set wapp $key $env($key) - } - } - set len 0 - if {[dict exists $wapp CONTENT_LENGTH]} { - set len [dict get $wapp CONTENT_LENGTH] - } - if {$len>0} { - fconfigure stdin -translation binary - dict set wapp CONTENT [read stdin $len] - } - dict set wapp WAPP_MODE cgi - fconfigure stdout -translation binary - wappInt-handle-request stdout 1 -} - -# Process new text received on an inbound SCGI request -# -proc wappInt-scgi-readable {chan} { - if {[catch [list wappInt-scgi-readable-unsafe $chan] msg]} { - puts stderr "$msg\n$::errorInfo" - wappInt-close-channel $chan - } -} -proc wappInt-scgi-readable-unsafe {chan} { - upvar #0 wappInt-$chan W wapp wapp - if {![dict exists $W .toread]} { - # If the .toread key is not set, that means we are still reading - # the header. - # - # An SGI header is short. This implementation assumes the entire - # header is available all at once. - # - dict set W .remove_addr [dict get $W REMOTE_ADDR] - set req [read $chan 15] - set n [string length $req] - scan $req %d:%s len hdr - incr len [string length "$len:,"] - append hdr [read $chan [expr {$len-15}]] - foreach {nm val} [split $hdr \000] { - if {$nm==","} break - dict set W $nm $val - } - set len 0 - if {[dict exists $W CONTENT_LENGTH]} { - set len [dict get $W CONTENT_LENGTH] - } - if {$len>0} { - # Still need to read the query content - dict set W .toread $len - } else { - # There is no query content, so handle the request immediately - dict set W SERVER_ADDR [dict get $W .remove_addr] - set wapp $W - wappInt-handle-request $chan 0 - } - } else { - # If .toread is set, that means we are reading the query content. - # Continue reading until .toread reaches zero. - set got [read $chan [dict get $W .toread]] - dict append W CONTENT $got - dict set W .toread [expr {[dict get $W .toread]-[string length $got]}] - if {[dict get $W .toread]<=0} { - # Handle the request as soon as all the query content is received - dict set W SERVER_ADDR [dict get $W .remove_addr] - set wapp $W - wappInt-handle-request $chan 0 - } - } -} - -# Start up the wapp framework. Parameters are a list passed as the -# single argument. -# -# -server $PORT Listen for HTTP requests on this TCP port $PORT -# -# -local $PORT Listen for HTTP requests on 127.0.0.1:$PORT -# -# -scgi $PORT Listen for SCGI requests on 127.0.0.1:$PORT -# -# -remote-scgi $PORT Listen for SCGI requests on TCP port $PORT -# -# -cgi Handle a single CGI request -# -# With no arguments, the behavior is called "auto". In "auto" mode, -# if the GATEWAY_INTERFACE environment variable indicates CGI, then run -# as CGI. Otherwise, start an HTTP server bound to the loopback address -# only, on an arbitrary TCP port, and automatically launch a web browser -# on that TCP port. -# -# Additional options: -# -# -fromip GLOB Reject any incoming request where the remote -# IP address does not match the GLOB pattern. This -# value defaults to '127.0.0.1' for -local and -scgi. -# -# -nowait Do not wait in the event loop. Return immediately -# after all event handlers are established. -# -# -trace "puts" each request URL as it is handled, for -# debugging -# -# -lint Run wapp-safety-check on the application instead -# of running the application itself -# -# -Dvar=value Set TCL global variable "var" to "value" -# -# -proc wapp-start {arglist} { - global env - set mode auto - set port 0 - set nowait 0 - set fromip {} - set n [llength $arglist] - for {set i 0} {$i<$n} {incr i} { - set term [lindex $arglist $i] - if {[string match --* $term]} {set term [string range $term 1 end]} - switch -glob -- $term { - -server { - incr i; - set mode "server" - set port [lindex $arglist $i] - } - -local { - incr i; - set mode "local" - set fromip 127.0.0.1 - set port [lindex $arglist $i] - } - -scgi { - incr i; - set mode "scgi" - set fromip 127.0.0.1 - set port [lindex $arglist $i] - } - -remote-scgi { - incr i; - set mode "remote-scgi" - set port [lindex $arglist $i] - } - -cgi { - set mode "cgi" - } - -fromip { - incr i - set fromip [lindex $arglist $i] - } - -nowait { - set nowait 1 - } - -trace { - proc wappInt-trace {} { - set q [wapp-param QUERY_STRING] - set uri [wapp-param BASE_URL][wapp-param PATH_INFO] - if {$q!=""} {append uri ?$q} - puts $uri - } - } - -lint { - set res [wapp-safety-check] - if {$res!=""} { - puts "Potential problems in this code:" - puts $res - exit 1 - } else { - exit - } - } - -D*=* { - if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} { - set ::$var $val - } - } - default { - error "unknown option: $term" - } - } - } - if {$mode=="auto"} { - if {[info exists env(GATEWAY_INTERFACE)] - && [string match CGI/1.* $env(GATEWAY_INTERFACE)]} { - set mode cgi - } else { - set mode local - } - } - if {$mode=="cgi"} { - wappInt-handle-cgi-request - } else { - wappInt-start-listener $port $mode $fromip - if {!$nowait} { - vwait ::forever - } - } -} - -# Call this version 1.0 -package provide wapp 1.0 diff --git a/test/wapptest.tcl b/test/wapptest.tcl deleted file mode 100755 index d37b2e48c6..0000000000 --- a/test/wapptest.tcl +++ /dev/null @@ -1,909 +0,0 @@ -#!/bin/sh -# \ -exec wapptclsh "$0" ${1+"$@"} - -# package required wapp -source [file join [file dirname [info script]] wapp.tcl] - -# Variables set by the "control" form: -# -# G(platform) - User selected platform. -# G(cfgglob) - Glob pattern that all configurations must match -# G(test) - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only". -# G(keep) - Boolean. True to delete no files after each test. -# G(msvc) - Boolean. True to use MSVC as the compiler. -# G(tcl) - Use Tcl from this directory for builds. -# G(jobs) - How many sub-processes to run simultaneously. -# -set G(platform) $::tcl_platform(os)-$::tcl_platform(machine) -set G(cfgglob) * -set G(test) Normal -set G(keep) 1 -set G(msvc) 0 -set G(tcl) [::tcl::pkgconfig get libdir,install] -set G(jobs) 3 -set G(debug) 0 - -set G(noui) 0 -set G(stdout) 0 - - -proc wapptest_init {} { - global G - - set lSave [list platform test keep msvc tcl jobs debug noui stdout cfgglob] - foreach k $lSave { set A($k) $G($k) } - array unset G - foreach k $lSave { set G($k) $A($k) } - - # The root of the SQLite source tree. - set G(srcdir) [file dirname [file dirname [info script]]] - - set G(sqlite_version) "unknown" - - # Either "config", "running" or "stopped": - set G(state) "config" - - set G(hostname) "(unknown host)" - catch { set G(hostname) [exec hostname] } - set G(host) $G(hostname) - append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)" - append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)" -} - -proc wapptest_run {} { - global G - set_test_array - set G(state) "running" - - wapptest_openlog - - wapptest_output "Running the following for $G(platform). $G(jobs) jobs." - foreach t $G(test_array) { - set config [dict get $t config] - set target [dict get $t target] - wapptest_output [format " %-25s%s" $config $target] - } - wapptest_output [string repeat * 70] -} - -proc releasetest_data {args} { - global G - set rtd [file join $G(srcdir) test releasetest_data.tcl] - set fd [open "|[info nameofexecutable] $rtd $args" r+] - set ret [read $fd] - close $fd - return $ret -} - -# Generate the text for the box at the top of the UI. The current SQLite -# version, according to fossil, along with a warning if there are -# uncommitted changes in the checkout. -# -proc generate_fossil_info {} { - global G - set pwd [pwd] - cd $G(srcdir) - set rc [catch { - set r1 [exec fossil info] - set r2 [exec fossil changes] - }] - cd $pwd - if {$rc} return - - foreach line [split $r1 "\n"] { - if {[regexp {^checkout: *(.*)$} $line -> co]} { - wapp-trim {
    %html($co) } - } - } - - if {[string trim $r2]!=""} { - wapp-trim { -
    - WARNING: Uncommitted changes in checkout - - } - } -} - -# If the application is in "config" state, set the contents of the -# ::G(test_array) global to reflect the tests that will be run. If the -# app is in some other state ("running" or "stopped"), this command -# is a no-op. -# -proc set_test_array {} { - global G - if { $G(state)=="config" } { - set G(test_array) [list] - set debug "-debug" - if {$G(debug)==0} { set debug "-nodebug"} - foreach {config target} [releasetest_data tests $debug $G(platform)] { - - # All configuration names must match $g(cfgglob), which defaults to * - # - if {![string match -nocase $G(cfgglob) $config]} continue - - # If using MSVC, do not run sanitize or valgrind tests. Or the - # checksymbols test. - if {$G(msvc) && ( - "Sanitize" == $config - || "checksymbols" in $target - || "valgrindtest" in $target - )} { - continue - } - - # If the test mode is not "Normal", override the target. - # - if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} { - switch -- $G(test) { - Veryquick { set target quicktest } - Smoketest { set target smoketest } - Build-Only { - set target testfixture - if {$::tcl_platform(platform)=="windows"} { - set target testfixture.exe - } - } - } - } - - lappend G(test_array) [dict create config $config target $target] - } - } -} - -proc count_tests_and_errors {name logfile} { - global G - - set fd [open $logfile rb] - set seen 0 - while {![eof $fd]} { - set line [gets $fd] - if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} { - incr G(test.$name.nError) $nerr - incr G(test.$name.nTest) $ntest - set seen 1 - if {$nerr>0} { - set G(test.$name.errmsg) $line - } - } - if {[regexp {runtime error: +(.*)} $line all msg]} { - # skip over "value is outside range" errors - if {[regexp {.* is outside the range of representable} $line]} { - # noop - } else { - incr G(test.$name.nError) - if {$G(test.$name.errmsg)==""} { - set G(test.$name.errmsg) $msg - } - } - } - if {[regexp {fatal error +(.*)} $line all msg]} { - incr G(test.$name.nError) - if {$G(test.$name.errmsg)==""} { - set G(test.$name.errmsg) $msg - } - } - if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { - incr G(test.$name.nError) - if {$G(test.$name.errmsg)==""} { - set G(test.$name.errmsg) $all - } - } - if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { - set v [string range $line 9 end] - if {$G(sqlite_version) eq "unknown"} { - set G(sqlite_version) $v - } elseif {$G(sqlite_version) ne $v} { - set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}" - } - } - } - close $fd - if {$G(test) == "Build-Only"} { - incr G(test.$name.nTest) - if {$G(test.$name.nError)>0} { - set errmsg "Build failed" - } - } elseif {!$seen} { - set G(test.$name.errmsg) "Test did not complete" - if {[file readable core]} { - append G(test.$name.errmsg) " - core file exists" - } - } -} - -proc wapptest_output {str} { - global G - if {$G(stdout)} { puts $str } - if {[info exists G(log)]} { - puts $G(log) $str - flush $G(log) - } -} -proc wapptest_openlog {} { - global G - set G(log) [open wapptest-out.txt w+] -} -proc wapptest_closelog {} { - global G - close $G(log) - unset G(log) -} - -proc format_seconds {seconds} { - set min [format %.2d [expr ($seconds / 60) % 60]] - set hr [format %.2d [expr $seconds / 3600]] - set sec [format %.2d [expr $seconds % 60]] - return "$hr:$min:$sec" -} - -# This command is invoked once a slave process has finished running its -# tests, successfully or otherwise. Parameter $name is the name of the -# test, $rc the exit code returned by the slave process. -# -proc slave_test_done {name rc} { - global G - set G(test.$name.done) [clock seconds] - set G(test.$name.nError) 0 - set G(test.$name.nTest) 0 - set G(test.$name.errmsg) "" - if {$rc} { - incr G(test.$name.nError) - } - if {[file exists $G(test.$name.log)]} { - count_tests_and_errors $name $G(test.$name.log) - } - - # If the "keep files" checkbox is clear, delete all files except for - # the executables and test logs. And any core file that is present. - if {$G(keep)==0} { - set keeplist { - testfixture testfixture.exe - sqlite3 sqlite3.exe - test.log test-out.txt - core - wapptest_make.sh - wapptest_configure.sh - wapptest_run.tcl - } - foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] { - set t [file tail $f] - if {[lsearch $keeplist $t]<0} { - catch { file delete -force $f } - } - } - } - - # Format a message regarding the success or failure of hte test. - set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]] - set res "OK" - if {$G(test.$name.nError)} { set res "FAILED" } - set dots [string repeat . [expr 60 - [string length $name]]] - set msg "$name $dots $res ($t)" - - wapptest_output $msg - if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} { - wapptest_output " $G(test.$name.errmsg)" - } -} - -# This is a fileevent callback invoked each time a file-descriptor that -# connects this process to a slave process is readable. -# -proc slave_fileevent {name} { - global G - set fd $G(test.$name.channel) - - if {[eof $fd]} { - fconfigure $fd -blocking 1 - set rc [catch { close $fd }] - unset G(test.$name.channel) - slave_test_done $name $rc - } else { - set line [gets $fd] - if {[string trim $line] != ""} { puts "Trace : $name - \"$line\"" } - } - - do_some_stuff -} - -# Return the contents of the "slave script" - the script run by slave -# processes to actually perform the test. All it does is execute the -# test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat). -# -proc wapptest_slave_script {} { - global G - if {$G(msvc)==0} { - set dir [file join .. $G(srcdir)] - set res [subst -nocommands { - set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ] - exit [set rc] - }] - } else { - set dir [file nativename [file normalize $G(srcdir)]] - set dir [string map [list "\\" "\\\\"] $dir] - set res [subst -nocommands { - set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ] - exit [set rc] - }] - } - - set res -} - - -# Launch a slave process to run a test. -# -proc slave_launch {name target dir} { - global G - - catch { file mkdir $dir } msg - foreach f [glob -nocomplain [file join $dir *]] { - catch { file delete -force $f } - } - set G(test.$name.dir) $dir - - # Write the test command to wapptest_cmd.sh|bat. - # - set ext sh - if {$G(msvc)} { set ext bat } - set fd1 [open [file join $dir wapptest_cmd.$ext] w] - if {$G(msvc)} { - puts $fd1 [releasetest_data script -msvc $name $target] - } else { - puts $fd1 [releasetest_data script $name $target] - } - close $fd1 - - # Write the wapptest_run.tcl script to the test directory. To run the - # commands in the other two files. - # - set fd3 [open [file join $dir wapptest_run.tcl] w] - puts $fd3 [wapptest_slave_script] - close $fd3 - - set pwd [pwd] - cd $dir - set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+] - cd $pwd - - set G(test.$name.channel) $fd - fconfigure $fd -blocking 0 - fileevent $fd readable [list slave_fileevent $name] -} - -proc do_some_stuff {} { - global G - - # Count the number of running jobs. A running job has an entry named - # "channel" in its dictionary. - set nRunning 0 - set bFinished 1 - foreach j $G(test_array) { - set name [dict get $j config] - if { [info exists G(test.$name.channel)]} { incr nRunning } - if {![info exists G(test.$name.done)]} { set bFinished 0 } - } - - if {$bFinished} { - set nError 0 - set nTest 0 - set nConfig 0 - foreach j $G(test_array) { - set name [dict get $j config] - incr nError $G(test.$name.nError) - incr nTest $G(test.$name.nTest) - incr nConfig - } - set G(result) "$nError errors from $nTest tests in $nConfig configurations." - wapptest_output [string repeat * 70] - wapptest_output $G(result) - catch { - append G(result) " SQLite version $G(sqlite_version)" - wapptest_output " SQLite version $G(sqlite_version)" - } - set G(state) "stopped" - wapptest_closelog - if {$G(noui)} { exit 0 } - } else { - set nLaunch [expr $G(jobs) - $nRunning] - foreach j $G(test_array) { - if {$nLaunch<=0} break - set name [dict get $j config] - if { ![info exists G(test.$name.channel)] - && ![info exists G(test.$name.done)] - } { - - set target [dict get $j target] - set dir [string tolower [string map {" " _ "-" _} $name]] - set G(test.$name.start) [clock seconds] - set G(test.$name.log) [file join $dir test.log] - - slave_launch $name $target $dir - - incr nLaunch -1 - } - } - } -} - -proc generate_select_widget {label id lOpt opt} { - wapp-trim { - - } -} - -proc generate_main_page {{extra {}}} { - global G - set_test_array - - set hostname $G(hostname) - wapp-trim { - - - %html($hostname): wapptest.tcl - - - - } - - set host $G(host) - wapp-trim { -
    %string($host) - } - generate_fossil_info - wapp-trim { -
    -
    -
    - } - - # Build the "platform" select widget. - set lOpt [releasetest_data platforms] - generate_select_widget Platform control_platform $lOpt $G(platform) - - # Build the "test" select widget. - set lOpt [list Normal Veryquick Smoketest Build-Only] - generate_select_widget Test control_test $lOpt $G(test) - - # Build the "jobs" select widget. Options are 1 to 8. - generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8 12 16} $G(jobs) - - switch $G(state) { - config { - set txt "Run Tests!" - set id control_run - } - running { - set txt "STOP Tests!" - set id control_stop - } - stopped { - set txt "Reset!" - set id control_reset - } - } - wapp-trim { -
    - - -
    - } - - wapp-trim { -

    - - - - - - - - - - - } - wapp-trim { -
    - } - wapp-trim { -
    -
    - } - wapp-page-tests - - set script "script/$G(state).js" - wapp-trim { -
    - - - - } -} - -proc wapp-default {} { - generate_main_page -} - -proc wapp-page-tests {} { - global G - wapp-trim { } - foreach t $G(test_array) { - set config [dict get $t config] - set target [dict get $t target] - - set class "testwait" - set seconds "" - - if {[info exists G(test.$config.log)]} { - if {[info exists G(test.$config.channel)]} { - set class "testrunning" - set seconds [expr [clock seconds] - $G(test.$config.start)] - } elseif {[info exists G(test.$config.done)]} { - if {$G(test.$config.nError)>0} { - set class "testfail" - } else { - set class "testdone" - } - set seconds [expr $G(test.$config.done) - $G(test.$config.start)] - } - set seconds [format_seconds $seconds] - } - - wapp-trim { - - -
    %html($config) - %html($target) - %html($seconds) - - } - if {[info exists G(test.$config.log)]} { - set log $G(test.$config.log) - set uri "log/$log" - wapp-trim { - %html($log) - } - } - if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} { - set errmsg $G(test.$config.errmsg) - wapp-trim { -
    %html($errmsg) - } - } - } - - wapp-trim {
    } - - if {[info exists G(result)]} { - set res $G(result) - wapp-trim { -
    %string($res)
    - } - } -} - -# URI: /control -# -# Whenever the form at the top of the application page is submitted, it -# is submitted here. -# -proc wapp-page-control {} { - global G - if {$::G(state)=="config"} { - set lControls [list platform test tcl jobs keep msvc debug] - set G(msvc) 0 - set G(keep) 0 - set G(debug) 0 - } else { - set lControls [list jobs] - } - foreach v $lControls { - if {[wapp-param-exists control_$v]} { - set G($v) [wapp-param control_$v] - } - } - - if {[wapp-param-exists control_run]} { - # This is a "run test" command. - wapptest_run - } - - if {[wapp-param-exists control_stop]} { - # A "STOP tests" command. - set G(state) "stopped" - set G(result) "Test halted by user" - foreach j $G(test_array) { - set name [dict get $j config] - if { [info exists G(test.$name.channel)] } { - close $G(test.$name.channel) - unset G(test.$name.channel) - slave_test_done $name 1 - } - } - wapptest_closelog - } - - if {[wapp-param-exists control_reset]} { - # A "reset app" command. - set G(state) "config" - wapptest_init - } - - if {$::G(state) == "running"} { - do_some_stuff - } - wapp-redirect / -} - -# URI: /style.css -# -# Return the stylesheet for the application main page. -# -proc wapp-page-style.css {} { - wapp-subst { - - /* The boxes with black borders use this class */ - .border { - border: 3px groove #444444; - padding: 1em; - margin-top: 1em; - margin-bottom: 1em; - } - - /* Float to the right (used for the Run/Stop/Reset button) */ - .right { float: right; } - - /* Style for the large red warning at the top of the page */ - .warning { - color: red; - font-weight: bold; - } - - /* Styles used by cells in the test table */ - .padleft { padding-left: 5ex; } - .nowrap { white-space: nowrap; } - - /* Styles for individual tests, depending on the outcome */ - .testwait { } - .testrunning { color: blue } - .testdone { color: green } - .testfail { color: red } - } -} - -# URI: /script/${state}.js -# -# The last part of this URI is always "config.js", "running.js" or -# "stopped.js", depending on the state of the application. It returns -# the javascript part of the front-end for the requested state to the -# browser. -# -proc wapp-page-script {} { - regexp {[^/]*$} [wapp-param REQUEST_URI] script - - set tcl $::G(tcl) - set keep $::G(keep) - set msvc $::G(msvc) - set debug $::G(debug) - - wapp-subst { - var lElem = \["control_platform", "control_test", "control_msvc", - "control_jobs", "control_debug" - \]; - lElem.forEach(function(e) { - var elem = document.getElementById(e); - elem.addEventListener("change", function() { control.submit() } ); - }) - - elem = document.getElementById("control_tcl"); - elem.value = "%string($tcl)" - - elem = document.getElementById("control_keep"); - elem.checked = %string($keep); - - elem = document.getElementById("control_msvc"); - elem.checked = %string($msvc); - - elem = document.getElementById("control_debug"); - elem.checked = %string($debug); - } - - if {$script != "config.js"} { - wapp-subst { - var lElem = \["control_platform", "control_test", - "control_tcl", "control_keep", "control_msvc", - "control_debug" - \]; - lElem.forEach(function(e) { - var elem = document.getElementById(e); - elem.disabled = true; - }) - } - } - - if {$script == "running.js"} { - wapp-subst { - function reload_tests() { - fetch('tests') - .then( data => data.text() ) - .then( data => { - document.getElementById("tests").innerHTML = data; - }) - .then( data => { - if( document.getElementById("result") ){ - document.location = document.location; - } else { - setTimeout(reload_tests, 1000) - } - }); - } - - setTimeout(reload_tests, 1000) - } - } -} - -# URI: /env -# -# This is for debugging only. Serves no other purpose. -# -proc wapp-page-env {} { - wapp-allow-xorigin-params - wapp-trim { -

    Wapp Environment

    \n
    -    
    %html([wapp-debug-env])
    - } -} - -# URI: /log/dirname/test.log -# -# This URI reads file "dirname/test.log" from disk, wraps it in a
    -# block, and returns it to the browser. Use for viewing log files.
    -#
    -proc wapp-page-log {} {
    -  set log [string range [wapp-param REQUEST_URI] 5 end]
    -  set fd [open $log]
    -  set data [read $fd]
    -  close $fd
    -  wapp-trim {
    -    
    -    %html($data)
    -    
    - } -} - -# Print out a usage message. Then do [exit 1]. -# -proc wapptest_usage {} { - puts stderr { -This Tcl script is used to test various configurations of SQLite. By -default it uses "wapp" to provide an interactive interface. Supported -command line options (all optional) are: - - --platform PLATFORM (which tests to run) - --config GLOB (only run configurations matching GLOB) - --smoketest (run "make smoketest" only) - --veryquick (run veryquick.test only) - --buildonly (build executables, do not run tests) - --jobs N (number of concurrent jobs) - --tcl DIR (where to find tclConfig.sh) - --deletefiles (delete extra files after each test) - --msvc (Use MS Visual C) - --debug (Also run [n]debugging versions of tests) - --noui (do not use wapp) - } - exit 1 -} - -# Sort command line arguments into two groups: those that belong to wapp, -# and those that belong to the application. -set WAPPARG(-server) 1 -set WAPPARG(-local) 1 -set WAPPARG(-scgi) 1 -set WAPPARG(-remote-scgi) 1 -set WAPPARG(-fromip) 1 -set WAPPARG(-nowait) 0 -set WAPPARG(-cgi) 0 -set lWappArg [list] -set lTestArg [list] -for {set i 0} {$i < [llength $argv]} {incr i} { - set arg [lindex $argv $i] - if {[string range $arg 0 1]=="--"} { - set arg [string range $arg 1 end] - } - if {[info exists WAPPARG($arg)]} { - lappend lWappArg $arg - if {$WAPPARG($arg)} { - incr i - lappend lWappArg [lindex $argv $i] - } - } else { - lappend lTestArg $arg - } -} - -wapptest_init -for {set i 0} {$i < [llength $lTestArg]} {incr i} { - set opt [lindex $lTestArg $i] - if {[string range $opt 0 1]=="--"} { - set opt [string range $opt 1 end] - } - switch -- $opt { - -platform { - if {$i==[llength $lTestArg]-1} { wapptest_usage } - incr i - set arg [lindex $lTestArg $i] - set lPlatform [releasetest_data platforms] - if {[lsearch $lPlatform $arg]<0} { - puts stderr "No such platform: $arg. Platforms are: $lPlatform" - exit -1 - } - set G(platform) $arg - } - - -smoketest { set G(test) Smoketest } - -veryquick { set G(test) Veryquick } - -buildonly { set G(test) Build-Only } - -jobs { - if {$i==[llength $lTestArg]-1} { wapptest_usage } - incr i - set G(jobs) [lindex $lTestArg $i] - } - - -tcl { - if {$i==[llength $lTestArg]-1} { wapptest_usage } - incr i - set G(tcl) [lindex $lTestArg $i] - } - - -deletefiles { - set G(keep) 0 - } - - -msvc { - set G(msvc) 1 - } - - -debug { - set G(debug) 1 - } - - -noui { - set G(noui) 1 - set G(stdout) 1 - } - - -config { - if {$i==[llength $lTestArg]-1} { wapptest_usage } - incr i - set G(cfgglob) [lindex $lTestArg $i] - } - - -stdout { - set G(stdout) 1 - } - - default { - puts stderr "Unrecognized option: [lindex $lTestArg $i]" - wapptest_usage - } - } -} - -if {$G(noui)==0} { - wapp-start $lWappArg -} else { - wapptest_run - do_some_stuff - vwait forever -} From 6234b334782b41db9aff8f8b688aba4e3f2b59bc Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 8 Nov 2023 15:56:41 +0000 Subject: [PATCH 32/55] Have the shell tool emit a warning if the user attempts to use ".scanstats vm" in a non-SQLITE_ENABLE_BYTECODE_VTAB build. FossilOrigin-Name: 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f8b0d56fd2..ea62075a91 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sold\sfiles\srelated\sto\swapptest.tcl\sfrom\stest/\sdirectory. -D 2023-11-08T15:51:42.810 +C Have\sthe\sshell\stool\semit\sa\swarning\sif\sthe\suser\sattempts\sto\suse\s".scanstats\svm"\sin\sa\snon-SQLITE_ENABLE_BYTECODE_VTAB\sbuild. +D 2023-11-08T15:56:41.847 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -725,7 +725,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 -F src/shell.c.in aebfbedaa7706d2c73ab7366a19fc8bc40ea68b70d2529f7feef54e6eb077ea2 +F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 @@ -2139,8 +2139,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 e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572 -R ce83d55831eeaab82518466b14d3660d +P dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe +R 6732486a2aaa0526e06e22748aa04499 U dan -Z aaf04791c4ef545a121de15f3eab560c +Z 4a970381aa1757bde9016fd89b987339 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 198e99f2b4..8a3f265a0b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe \ No newline at end of file +3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 3cfe1a94a4..8d201bbbda 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -10074,8 +10074,14 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_db_config( p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0 ); -#ifndef SQLITE_ENABLE_STMT_SCANSTATUS +#if !defined(SQLITE_ENABLE_STMT_SCANSTATUS) raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); +#elif !defined(SQLITE_ENABLE_BYTECODE_VTAB) + if( p->scanstatsOn==3 ){ + raw_printf(stderr, + "Warning: \".scanstats vm\" not available in this build.\n" + ); + } #endif }else{ raw_printf(stderr, "Usage: .scanstats on|off|est\n"); From b494366370f5f9698e574150c5a4309d7c3dc78b Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Nov 2023 16:37:12 +0000 Subject: [PATCH 33/55] More precise characterization of JSON functions. Indicate when functions might return JSON (subtype 'J') and when they make use of the function argument cache. FossilOrigin-Name: b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/json.c | 43 +++++++++++++++++++++++-------------------- src/sqliteInt.h | 6 +++--- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/manifest b/manifest index ea62075a91..d580ab0fb8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\sthe\sshell\stool\semit\sa\swarning\sif\sthe\suser\sattempts\sto\suse\s".scanstats\svm"\sin\sa\snon-SQLITE_ENABLE_BYTECODE_VTAB\sbuild. -D 2023-11-08T15:56:41.847 +C More\sprecise\scharacterization\sof\sJSON\sfunctions.\s\sIndicate\swhen\sfunctions\smight\nreturn\sJSON\s(subtype\s'J')\sand\swhen\sthey\smake\suse\sof\sthe\sfunction\sargument\scache. +D 2023-11-08T16:37:12.211 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -684,7 +684,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c d69c6e28ff7b602877bda68cd20583b8487c059759aa4d154dd21b3fd99c6238 +F src/json.c 82d1237899d5d06dc9722f9a0d9305711ff563c68221b479f0788b33cb114e16 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/main.c e1bc8864834697503d370d94613be945d05ca1c5ebdda43e7d5c8ee8c48d433c @@ -729,7 +729,7 @@ F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1 F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h b9f6cfac999b60def4d3523897dc1f5453ab9c24195e462fd346476541cf659a +F src/sqliteInt.h 90bbf1ba8f47753c84f15cdb0e5dc6267d3f391cc66b9fbd6f441881d1bf44a1 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -2139,8 +2139,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 dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe -R 6732486a2aaa0526e06e22748aa04499 -U dan -Z 4a970381aa1757bde9016fd89b987339 +P 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a +R 2a4b96e0d45f1ec3b63228c066f1d6da +U drh +Z 7680e031e38ed1a9d942d233bb859fec # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8a3f265a0b..8ca67c6ccf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a \ No newline at end of file +b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f \ No newline at end of file diff --git a/src/json.c b/src/json.c index c2129a026e..407ca2d0eb 100644 --- a/src/json.c +++ b/src/json.c @@ -3804,27 +3804,30 @@ static sqlite3_module jsonTreeModule = { void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { - JFUNCTION(json, 1, 0, jsonRemoveFunc), - JFUNCTION(json_array, -1, 0, jsonArrayFunc), - JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), - JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), - JFUNCTION(json_error_position,1, 0, jsonErrorFunc), - JFUNCTION(json_extract, -1, 0, jsonExtractFunc), - JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc), - JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc), - JFUNCTION(json_insert, -1, 0, jsonSetFunc), - JFUNCTION(json_object, -1, 0, jsonObjectFunc), - JFUNCTION(json_patch, 2, 0, jsonPatchFunc), - JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), - JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), - JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), - JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc), - JFUNCTION(json_type, 1, 0, jsonTypeFunc), - JFUNCTION(json_type, 2, 0, jsonTypeFunc), - JFUNCTION(json_valid, 1, 0, jsonValidFunc), + /* Uses cache ------, ,---- Might return JSON (subtype J) */ + /* Num args ________ | | ___ Flags */ + /* \ | | / */ + JFUNCTION(json, 1, 1, 1, 0, jsonRemoveFunc), + JFUNCTION(json_array, -1, 0, 1, 0, jsonArrayFunc), + JFUNCTION(json_array_length, 1, 1, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_array_length, 2, 1, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_error_position,1, 1, 0, 0, jsonErrorFunc), + JFUNCTION(json_extract, -1, 1, 1, 0, jsonExtractFunc), + JFUNCTION(->, 2, 1, 1, JSON_JSON, jsonExtractFunc), + JFUNCTION(->>, 2, 1, 0, JSON_SQL, jsonExtractFunc), + JFUNCTION(json_insert, -1, 1, 1, 0, jsonSetFunc), + JFUNCTION(json_object, -1, 0, 1, 0, jsonObjectFunc), + JFUNCTION(json_patch, 2, 1, 1, 0, jsonPatchFunc), + JFUNCTION(json_quote, 1, 0, 1, 0, jsonQuoteFunc), + JFUNCTION(json_remove, -1, 1, 1, 0, jsonRemoveFunc), + JFUNCTION(json_replace, -1, 1, 1, 0, jsonReplaceFunc), + JFUNCTION(json_set, -1, 1, 1, JSON_ISSET, jsonSetFunc), + JFUNCTION(json_type, 1, 1, 0, 0, jsonTypeFunc), + JFUNCTION(json_type, 2, 1, 0, 0, jsonTypeFunc), + JFUNCTION(json_valid, 1, 1, 0, 0, jsonValidFunc), #if SQLITE_DEBUG - JFUNCTION(json_parse, 1, 0, jsonParseFunc), - JFUNCTION(json_test1, 1, 0, jsonTest1Func), + JFUNCTION(json_parse, 1, 1, 0, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 1, 0, 0, jsonTest1Func), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1a22500539..20e23ed2bc 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2113,9 +2113,9 @@ struct FuncDestructor { #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } -#define JFUNCTION(zName, nArg, iArg, xFunc) \ - {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\ - SQLITE_FUNC_CONSTANT|SQLITE_UTF8|SQLITE_FUNC_RUNONLY, \ +#define JFUNCTION(zName, nArg, bUseCache, bSubtype, iArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ + SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|((bSubtype)*SQLITE_SUBTYPE), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ From 2cbe14098b156838153f194df1ea41d9b390935b Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Nov 2023 18:08:07 +0000 Subject: [PATCH 34/55] Do not cover expressions using an indexed expression if the indexed expression is a function that might set a subtype. FossilOrigin-Name: e908b26a990929996b3c16f0429e8313cd8fcefe7c883c77f66ea69f4059d6e2 --- manifest | 17 ++++++++++------- manifest.uuid | 2 +- src/where.c | 11 +++++++++++ test/indexexpr1.test | 14 ++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d580ab0fb8..6996862b81 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sprecise\scharacterization\sof\sJSON\sfunctions.\s\sIndicate\swhen\sfunctions\smight\nreturn\sJSON\s(subtype\s'J')\sand\swhen\sthey\smake\suse\sof\sthe\sfunction\sargument\scache. -D 2023-11-08T16:37:12.211 +C Do\snot\scover\sexpressions\susing\san\sindexed\sexpression\sif\sthe\sindexed\sexpression\nis\sa\sfunction\sthat\smight\sset\sa\ssubtype. +D 2023-11-08T18:08:07.513 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -809,7 +809,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 313ce81270d2a414672370e1ee74e65949ad620519193d4cac2986d073cbc8a0 +F src/where.c 431309d7920383671b05d43454351230eb9c01d963a6f7d4a516334cbbcce1d4 F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 @@ -1269,7 +1269,7 @@ F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a91 F test/index9.test 2ac891806a4136ef3e91280477e23114e67575207dc331e6797fa0ed9379f997 F test/indexA.test 11d84f6995e6e5b9d8315953fb1b6d29772ee7c7803ee9112715e7e4dd3e4974 F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0 -F test/indexexpr1.test 62558b1cfd7ccbe7bc015849cc6d1a13ef124e80cbd5b3a98dc66c3c9cce0cf4 +F test/indexexpr1.test 833f511213a5e26549186813f0566bd72f978177a7e6e98a2d2dd695de3c670d F test/indexexpr2.test 1c382e81ef996d8ae8b834a74f2a9013dddf59214c32201d7c8a656d739f999a F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 @@ -2139,8 +2139,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a -R 2a4b96e0d45f1ec3b63228c066f1d6da +P b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f +R 3699dfa06af6d8dfe43187d2c78cc578 +T *branch * idx-expr-fix +T *sym-idx-expr-fix * +T -sym-trunk * U drh -Z 7680e031e38ed1a9d942d233bb859fec +Z 99b5085d0aa63df2f84ecba864ce3e16 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8ca67c6ccf..303299d818 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f \ No newline at end of file +e908b26a990929996b3c16f0429e8313cd8fcefe7c883c77f66ea69f4059d6e2 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 05ae24f7bc..cfee45f879 100644 --- a/src/where.c +++ b/src/where.c @@ -5810,6 +5810,17 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; + if( pExpr->op==TK_FUNCTION ){ + int n; + FuncDef *pDef; + sqlite3 *db = pParse->db; + assert( ExprUseXList(pExpr) ); + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); + if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_SUBTYPE)!=0 ){ + continue; + } + } p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; diff --git a/test/indexexpr1.test b/test/indexexpr1.test index 51ef73bbf5..0316ee9d42 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -616,4 +616,18 @@ do_execsql_test indexexpr1-2200 { ) v ON v.type = 0 AND v.tag = u.tag; } {7 100 8 101} +# 2023-11-08 Forum post https://sqlite.org/forum/forumpost/68d284c86b082c3e +# +# Functions that return subtypes and that are indexed cannot be used to +# cover function calls from the main table, since the indexed value does +# not know the subtype. +# +reset_db +do_execsql_test indexexpr1-2300 { + CREATE TABLE t1(x INT, y TEXT); + INSERT INTO t1(x,y) VALUES(1,'{b:5}'); + CREATE INDEX t1j ON t1(json(y)); + SELECT json_insert('{}', '$.a', json(y)) FROM t1; +} {{{"a":{"b":5}}}} + finish_test From 243f2ec6a15201fdcabc791fd7618d85332fe83f Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Nov 2023 21:38:30 +0000 Subject: [PATCH 35/55] Make a distinction between functions that consume subtypes and functions that generate subtypes. FossilOrigin-Name: 48a92e3ad855227188a4c5afe4abbb7171761cf6fc930660084d9abeecfd91d9 --- manifest | 21 +++++++++++-------- manifest.uuid | 2 +- src/json.c | 56 +++++++++++++++++++++++++++---------------------- src/sqlite.h.in | 33 ++++++++++++++++++++++------- src/sqliteInt.h | 10 +++++---- src/window.c | 2 +- 6 files changed, 76 insertions(+), 48 deletions(-) diff --git a/manifest b/manifest index d580ab0fb8..bf5ccb0dc0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sprecise\scharacterization\sof\sJSON\sfunctions.\s\sIndicate\swhen\sfunctions\smight\nreturn\sJSON\s(subtype\s'J')\sand\swhen\sthey\smake\suse\sof\sthe\sfunction\sargument\scache. -D 2023-11-08T16:37:12.211 +C Make\sa\sdistinction\sbetween\sfunctions\sthat\sconsume\ssubtypes\sand\sfunctions\nthat\sgenerate\ssubtypes. +D 2023-11-08T21:38:30.966 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -684,7 +684,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c 82d1237899d5d06dc9722f9a0d9305711ff563c68221b479f0788b33cb114e16 +F src/json.c 7fe43f314870b0c351b3b62fadd75ca74a4bd848074aa87989256667b16b4ba8 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/main.c e1bc8864834697503d370d94613be945d05ca1c5ebdda43e7d5c8ee8c48d433c @@ -726,10 +726,10 @@ F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f -F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd +F src/sqlite.h.in bf3c06da94f5857ab49f9573d2c5f095210526eca948e51c931db63c431d5f8d F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h 90bbf1ba8f47753c84f15cdb0e5dc6267d3f391cc66b9fbd6f441881d1bf44a1 +F src/sqliteInt.h b2a8e6ec78aaed2443966d374b1e8fd623dc6c1a149736363d9cbe2af824950e F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -813,7 +813,7 @@ F src/where.c 313ce81270d2a414672370e1ee74e65949ad620519193d4cac2986d073cbc8a0 F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 -F src/window.c ad21e2b73ec75acc79dde2576c573f54a338b0c49e9de847ce984f9b9595b5e2 +F src/window.c 6f46006904c53783c46aaae1a5ec30c42b632e624c6c30f2b6688e8703aa404d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9 @@ -2139,8 +2139,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a -R 2a4b96e0d45f1ec3b63228c066f1d6da +P b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f +R 18013744e98b85d7b88e0e681a0596bb +T *branch * func-rw-subtype +T *sym-func-rw-subtype * +T -sym-trunk * U drh -Z 7680e031e38ed1a9d942d233bb859fec +Z 7575eb9b47eda5f1a399d46eb9d53d9f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8ca67c6ccf..0c5a28466d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f \ No newline at end of file +48a92e3ad855227188a4c5afe4abbb7171761cf6fc930660084d9abeecfd91d9 \ No newline at end of file diff --git a/src/json.c b/src/json.c index 407ca2d0eb..ab6939d029 100644 --- a/src/json.c +++ b/src/json.c @@ -3804,37 +3804,43 @@ static sqlite3_module jsonTreeModule = { void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { - /* Uses cache ------, ,---- Might return JSON (subtype J) */ - /* Num args ________ | | ___ Flags */ - /* \ | | / */ - JFUNCTION(json, 1, 1, 1, 0, jsonRemoveFunc), - JFUNCTION(json_array, -1, 0, 1, 0, jsonArrayFunc), - JFUNCTION(json_array_length, 1, 1, 0, 0, jsonArrayLengthFunc), - JFUNCTION(json_array_length, 2, 1, 0, 0, jsonArrayLengthFunc), - JFUNCTION(json_error_position,1, 1, 0, 0, jsonErrorFunc), - JFUNCTION(json_extract, -1, 1, 1, 0, jsonExtractFunc), - JFUNCTION(->, 2, 1, 1, JSON_JSON, jsonExtractFunc), - JFUNCTION(->>, 2, 1, 0, JSON_SQL, jsonExtractFunc), - JFUNCTION(json_insert, -1, 1, 1, 0, jsonSetFunc), - JFUNCTION(json_object, -1, 0, 1, 0, jsonObjectFunc), - JFUNCTION(json_patch, 2, 1, 1, 0, jsonPatchFunc), - JFUNCTION(json_quote, 1, 0, 1, 0, jsonQuoteFunc), - JFUNCTION(json_remove, -1, 1, 1, 0, jsonRemoveFunc), - JFUNCTION(json_replace, -1, 1, 1, 0, jsonReplaceFunc), - JFUNCTION(json_set, -1, 1, 1, JSON_ISSET, jsonSetFunc), - JFUNCTION(json_type, 1, 1, 0, 0, jsonTypeFunc), - JFUNCTION(json_type, 2, 1, 0, 0, jsonTypeFunc), - JFUNCTION(json_valid, 1, 1, 0, 0, jsonValidFunc), + /* calls sqlite3_result_subtype() */ + /* | */ + /* Uses cache ______ | __ calls sqlite3_value_subtype() */ + /* | | | */ + /* Num args _________ | | | ___ Flags */ + /* | | | | | */ + /* | | | | | */ + JFUNCTION(json, 1, 1, 1, 0, 0, jsonRemoveFunc), + JFUNCTION(json_array, -1, 0, 1, 1, 0, jsonArrayFunc), + JFUNCTION(json_array_length, 1, 1, 0, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_array_length, 2, 1, 0, 0, 0, jsonArrayLengthFunc), + JFUNCTION(json_error_position,1, 1, 0, 0, 0, jsonErrorFunc), + JFUNCTION(json_extract, -1, 1, 1, 0, 0, jsonExtractFunc), + JFUNCTION(->, 2, 1, 1, 0, JSON_JSON, jsonExtractFunc), + JFUNCTION(->>, 2, 1, 0, 0, JSON_SQL, jsonExtractFunc), + JFUNCTION(json_insert, -1, 1, 1, 1, 0, jsonSetFunc), + JFUNCTION(json_object, -1, 0, 1, 1, 0, jsonObjectFunc), + JFUNCTION(json_patch, 2, 1, 1, 0, 0, jsonPatchFunc), + JFUNCTION(json_quote, 1, 0, 1, 1, 0, jsonQuoteFunc), + JFUNCTION(json_remove, -1, 1, 1, 0, 0, jsonRemoveFunc), + JFUNCTION(json_replace, -1, 1, 1, 1, 0, jsonReplaceFunc), + JFUNCTION(json_set, -1, 1, 1, 1, JSON_ISSET, jsonSetFunc), + JFUNCTION(json_type, 1, 1, 0, 0, 0, jsonTypeFunc), + JFUNCTION(json_type, 2, 1, 0, 0, 0, jsonTypeFunc), + JFUNCTION(json_valid, 1, 1, 0, 0, 0, jsonValidFunc), #if SQLITE_DEBUG - JFUNCTION(json_parse, 1, 1, 0, 0, jsonParseFunc), - JFUNCTION(json_test1, 1, 1, 0, 0, jsonTest1Func), + JFUNCTION(json_parse, 1, 1, 1, 0, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 1, 0, 1, 0, jsonTest1Func), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), + SQLITE_VALUE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_DETERMINISTIC), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC) + SQLITE_VALUE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_DETERMINISTIC) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); #endif diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2317d98f79..2853289fcd 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5572,21 +5572,38 @@ int sqlite3_create_window_function( ** security-adverse side-effects and information-leaks. ** ** -** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** [[SQLITE_VALUE_SUBTYPE]]
    SQLITE_VALUE_SUBTYPE
    +** The SQLITE_VALUE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** Specifying this flag makes no difference for scalar or aggregate user -** functions. However, if it is not specified for a user-defined window -** function, then any sub-types belonging to arguments passed to the window -** function may be discarded before the window function is called (i.e. -** sqlite3_value_subtype() will always return 0). +** Every function that invokes [sqlite3_value_subtype()] should have this +** property. If it does not, then the query planner might generate +** incorrect code for queries that use that function. This property +** used to be called [SQLITE_SUBTYPE]. Its name was changed to disinguish +** it from [SQLITE_RESULT_SUBTYPE]. The old name is also retained for +** backwards compatibility. +** +** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    +** The SQLITE_SUBTYPE flag is an alias for [SQLITE_VALUE_SUBTYPE] used for +** backwards compatibility. The newer [SQLITE_VALUE_SUBTYPE] +** symbol is preferred. +** +** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    +** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call +** [sqlite3_result_subtype()] to cause a sub-type to be associated with its +** result. +** Every function that invokes [sqlite3_result_subtype()] should have this +** property. If it does not, then the call to [sqlite3_result_subtype()] +** might become a no-op if the function is used as term in an +** [expression index]. **
    ** */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 -#define SQLITE_SUBTYPE 0x000100000 +#define SQLITE_SUBTYPE 0x000100000 /* Deprecated name */ +#define SQLITE_VALUE_SUBTYPE 0x000100000 /* Use instead of SQLITE_SUBTYPE */ #define SQLITE_INNOCUOUS 0x000200000 +#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 20e23ed2bc..1a1e1268a4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2018,10 +2018,11 @@ struct FuncDestructor { #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ -#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ +/* SQLITE_VALUE_SUBTYPE 0x00100000 // Consumer of subtypes */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ +/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */ #define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ @@ -2113,9 +2114,10 @@ struct FuncDestructor { #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } -#define JFUNCTION(zName, nArg, bUseCache, bSubtype, iArg, xFunc) \ +#define JFUNCTION(zName, nArg, bUseCache, bRS, bWS, iArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ - SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|((bSubtype)*SQLITE_SUBTYPE), \ + SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ + ((bRS)*SQLITE_VALUE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ @@ -4452,7 +4454,7 @@ struct Window { int regStartRowid; int regEndRowid; u8 bExprArgs; /* Defer evaluation of window function arguments - ** due to the SQLITE_SUBTYPE flag */ + ** due to the SQLITE_VALUE_SUBTYPE flag */ }; #ifndef SQLITE_OMIT_WINDOWFUNC diff --git a/src/window.c b/src/window.c index 2c449592d7..edbfb6c7e0 100644 --- a/src/window.c +++ b/src/window.c @@ -1038,7 +1038,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; - if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ + if( pWin->pWFunc->funcFlags & SQLITE_VALUE_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; From c060b5f3a880e487e4ee6008317bef593fb6e5cf Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 01:54:26 +0000 Subject: [PATCH 36/55] JSON5 bug fix: Escape double-quotes that occur inside of single-quoted strings. [forum:/forumpost/ddcad3e884|Forum post ddcad3e884]. FossilOrigin-Name: 1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/json.c | 8 +++++++- test/json501.test | 5 +++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index d580ab0fb8..6414fd487b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sprecise\scharacterization\sof\sJSON\sfunctions.\s\sIndicate\swhen\sfunctions\smight\nreturn\sJSON\s(subtype\s'J')\sand\swhen\sthey\smake\suse\sof\sthe\sfunction\sargument\scache. -D 2023-11-08T16:37:12.211 +C JSON5\sbug\sfix:\s\sEscape\sdouble-quotes\sthat\soccur\sinside\sof\ssingle-quoted\sstrings.\n[forum:/forumpost/ddcad3e884|Forum\spost\sddcad3e884]. +D 2023-11-09T01:54:26.529 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -684,7 +684,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c 82d1237899d5d06dc9722f9a0d9305711ff563c68221b479f0788b33cb114e16 +F src/json.c 78559ef0eb3929c693ee2cd69fe5187fba8b123edb97cbd1c6a8dcd0589310ac F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/main.c e1bc8864834697503d370d94613be945d05ca1c5ebdda43e7d5c8ee8c48d433c @@ -1325,7 +1325,7 @@ F test/json102.test 4c69694773a470f1fda34e5f4ba24920b35184fb66050b450fc2ef9ab5ad F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1 F test/json105.test 11670a4387f4308ae0318cadcbd6a918ea7edcd19fbafde020720a073952675d -F test/json501.test f71710f60fa45b19dc336fbaac9e8362f70f80cf81badefdb845ed3f7c7c2ccc +F test/json501.test c419deb835b70c1a2c8532936927bcc1146730328edd2052276715bfd209724d F test/json502.test 98c38e3c4573841028a1381dfb81d4c3f9b105d39668167da10d055e503f6d0b F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/kvtest.c 6e0228409ea7ca0497dad503fbd109badb5e59545d131014b6aaac68b56f484a @@ -2139,8 +2139,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 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a -R 2a4b96e0d45f1ec3b63228c066f1d6da +P b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f +R bc8e127289d5f1279e134e74ad50d503 U drh -Z 7680e031e38ed1a9d942d233bb859fec +Z 7d193c1105cecb8c78a50905b1669eb7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8ca67c6ccf..17aa7a9f38 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f \ No newline at end of file +1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0 \ No newline at end of file diff --git a/src/json.c b/src/json.c index 407ca2d0eb..91b96df376 100644 --- a/src/json.c +++ b/src/json.c @@ -432,13 +432,19 @@ static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){ zIn++; N -= 2; while( N>0 ){ - for(i=0; i0 ){ jsonAppendRawNZ(p, zIn, i); zIn += i; N -= i; if( N==0 ) break; } + if( zIn[0]=='"' ){ + jsonAppendRawNZ(p, "\\\"", 2); + zIn++; + N--; + continue; + } assert( zIn[0]=='\\' ); switch( (u8)zIn[1] ){ case '\'': diff --git a/test/json501.test b/test/json501.test index a37326973a..3318eea7f2 100644 --- a/test/json501.test +++ b/test/json501.test @@ -300,5 +300,10 @@ do_execsql_test 12.4 { || ' "xyz"}')->>'a'; } xyz +# 2023-11-08 forum/forumpost/ddcad3e884 +# +do_execsql_test 13.1 { + SELECT json('{x:''a "b" c''}'); +} {{{"x":"a \"b\" c"}}} finish_test From ec427813ac5ac9857fbfa0073875cc940dc066d1 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 9 Nov 2023 12:01:02 +0000 Subject: [PATCH 37/55] Two more JNI build fixes for Windows/MinGW, reported in [forum:4f949edc312d2a75|forum post 4f949edc312d2a75]. FossilOrigin-Name: a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4 --- ext/jni/GNUmakefile | 2 ++ .../src/org/sqlite/jni/capi/sqlite3_blob.java | 2 +- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index 61c816194f..dc93f49085 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -35,6 +35,8 @@ $(dir.bld.c): javac.flags ?= -Xlint:unchecked -Xlint:deprecation java.flags ?= +javac.flags += -encoding utf8 +# -------------^^^^^^^^^^^^^^ required for Windows builds jnicheck ?= 1 ifeq (1,$(jnicheck)) java.flags += -Xcheck:jni diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java index 1b96c18b06..4bca3363ff 100644 --- a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java +++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java @@ -25,7 +25,7 @@ public final class sqlite3_blob extends NativePointerHolder private sqlite3_blob(){} @Override public void close(){ - CApi.sqlite3_blob_close(this.clearNativePointer()); + CApi.sqlite3_blob_close(this); } } diff --git a/manifest b/manifest index 6414fd487b..f6390adef5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JSON5\sbug\sfix:\s\sEscape\sdouble-quotes\sthat\soccur\sinside\sof\ssingle-quoted\sstrings.\n[forum:/forumpost/ddcad3e884|Forum\spost\sddcad3e884]. -D 2023-11-09T01:54:26.529 +C Two\smore\sJNI\sbuild\sfixes\sfor\sWindows/MinGW,\sreported\sin\s[forum:4f949edc312d2a75|forum\spost\s4f949edc312d2a75]. +D 2023-11-09T12:01:02.729 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -238,7 +238,7 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 -F ext/jni/GNUmakefile df91212d772011e3d39712a0e38586856c42528b6ee3d507a5bb3b3248c0ecbc +F ext/jni/GNUmakefile d984ea9c4e3536188f9d663120db8fb97b83329f4b8864bd88f75ebe581b8b8b F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 6b95974189d7cc394afbe15507050f1d174170a65be5a4dad201ab11f0a9777a @@ -278,7 +278,7 @@ F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba90943 F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e F ext/jni/src/org/sqlite/jni/capi/sqlite3.java c6a5c555d163d76663534f2b2cce7cab15325b9852d0f58c6688a85e73ae52f0 F ext/jni/src/org/sqlite/jni/capi/sqlite3_backup.java 6742b431cd4d77e8000c1f92ec66265a58414c86bf3b0b5fbcb1164e08477227 -F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java f204ab6ab1263e119fe43730141a00662d80972129a5351dfb11aae5d282df36 +F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java e8c799ed89a7725ba779ff7d4b1d941c5aaae1b1c3888a68a10ee9cca5c71e7d F ext/jni/src/org/sqlite/jni/capi/sqlite3_context.java f0ef982009c335c4393ffcb68051809ca1711e4f47bcb8d1d46952f22c01bc22 F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java 293b5fa7d5b5724c87de544654aca1103d76f3092bc2c8f4360102a65ba25dff F ext/jni/src/org/sqlite/jni/capi/sqlite3_value.java e1d62a257c13504b46d39d5c21c49cf157ad73fda00cc5f34c931aa008c37049 @@ -2139,8 +2139,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 b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f -R bc8e127289d5f1279e134e74ad50d503 -U drh -Z 7d193c1105cecb8c78a50905b1669eb7 +P 1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0 +R 17c07891ab0f75a8281c2b918fd5c523 +U stephan +Z 19240fed0f90b5e1367576a460d156b0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 17aa7a9f38..300175f17c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0 \ No newline at end of file +a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4 \ No newline at end of file From 194b8d514bc8ba594e88c93cfaba66ff24d00ae8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 12:08:16 +0000 Subject: [PATCH 38/55] Omit the new SQLITE_VALUE_SUBTYPE name. Stay with legacy SQLTIE_SUBTYPE. Add extra documentation to sqlite3_value_subtype() and sqlite3_result_subtype() indicating that the SQLITE_SUBTYPE and SQLITE_RESULT_SUBTYPE properties are required on functions that use those interfaces. FossilOrigin-Name: 563ad3be60d22c45f1c5b9a3e67738593f8b38f137147c56514166fbabf95365 --- manifest | 21 +++++++++------------ manifest.uuid | 2 +- src/json.c | 4 ++-- src/sqlite.h.in | 37 +++++++++++++++++++++++-------------- src/sqliteInt.h | 6 +++--- src/window.c | 2 +- 6 files changed, 39 insertions(+), 33 deletions(-) diff --git a/manifest b/manifest index bf5ccb0dc0..f9b734176e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sa\sdistinction\sbetween\sfunctions\sthat\sconsume\ssubtypes\sand\sfunctions\nthat\sgenerate\ssubtypes. -D 2023-11-08T21:38:30.966 +C Omit\sthe\snew\sSQLITE_VALUE_SUBTYPE\sname.\s\sStay\swith\slegacy\sSQLTIE_SUBTYPE.\nAdd\sextra\sdocumentation\sto\ssqlite3_value_subtype()\sand\ssqlite3_result_subtype()\nindicating\sthat\sthe\sSQLITE_SUBTYPE\sand\sSQLITE_RESULT_SUBTYPE\sproperties\sare\nrequired\son\sfunctions\sthat\suse\sthose\sinterfaces. +D 2023-11-09T12:08:16.633 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -684,7 +684,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c 7fe43f314870b0c351b3b62fadd75ca74a4bd848074aa87989256667b16b4ba8 +F src/json.c bf117324d2efff47b392c29f7d3e611a7508933b91491c7ad349101e6d5f5e05 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/main.c e1bc8864834697503d370d94613be945d05ca1c5ebdda43e7d5c8ee8c48d433c @@ -726,10 +726,10 @@ F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f -F src/sqlite.h.in bf3c06da94f5857ab49f9573d2c5f095210526eca948e51c931db63c431d5f8d +F src/sqlite.h.in 8da45c84e79cde72c73fcb4260addcc7c00fac3bc6f5594b81a3792c1b196264 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 -F src/sqliteInt.h b2a8e6ec78aaed2443966d374b1e8fd623dc6c1a149736363d9cbe2af824950e +F src/sqliteInt.h fe1bc1d3ee5302bb8e6b7284cd900bed2d4dd402d08d2893c055afe7297249a8 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -813,7 +813,7 @@ F src/where.c 313ce81270d2a414672370e1ee74e65949ad620519193d4cac2986d073cbc8a0 F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 -F src/window.c 6f46006904c53783c46aaae1a5ec30c42b632e624c6c30f2b6688e8703aa404d +F src/window.c 5b1387d59df30d481ed14cceef5f4d1dab1f8752aa106ba72c8b62777bd139d2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9 @@ -2139,11 +2139,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 b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f -R 18013744e98b85d7b88e0e681a0596bb -T *branch * func-rw-subtype -T *sym-func-rw-subtype * -T -sym-trunk * +P 48a92e3ad855227188a4c5afe4abbb7171761cf6fc930660084d9abeecfd91d9 +R 1125c8580bcae0bd5fcad566907cd268 U drh -Z 7575eb9b47eda5f1a399d46eb9d53d9f +Z b355d7c6c1259a41f882f80ab53c48da # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0c5a28466d..74e16885c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -48a92e3ad855227188a4c5afe4abbb7171761cf6fc930660084d9abeecfd91d9 \ No newline at end of file +563ad3be60d22c45f1c5b9a3e67738593f8b38f137147c56514166fbabf95365 \ No newline at end of file diff --git a/src/json.c b/src/json.c index ab6939d029..132a274cd3 100644 --- a/src/json.c +++ b/src/json.c @@ -3835,11 +3835,11 @@ void sqlite3RegisterJsonFunctions(void){ #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - SQLITE_VALUE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| SQLITE_DETERMINISTIC), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - SQLITE_VALUE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| SQLITE_DETERMINISTIC) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2853289fcd..09e6f47653 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5572,20 +5572,12 @@ int sqlite3_create_window_function( ** security-adverse side-effects and information-leaks. ** ** -** [[SQLITE_VALUE_SUBTYPE]]
    SQLITE_VALUE_SUBTYPE
    -** The SQLITE_VALUE_SUBTYPE flag indicates to SQLite that a function may call +** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. ** Every function that invokes [sqlite3_value_subtype()] should have this ** property. If it does not, then the query planner might generate -** incorrect code for queries that use that function. This property -** used to be called [SQLITE_SUBTYPE]. Its name was changed to disinguish -** it from [SQLITE_RESULT_SUBTYPE]. The old name is also retained for -** backwards compatibility. -** -** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag is an alias for [SQLITE_VALUE_SUBTYPE] used for -** backwards compatibility. The newer [SQLITE_VALUE_SUBTYPE] -** symbol is preferred. +** incorrect code for queries that use that function. ** ** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    ** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call @@ -5594,14 +5586,16 @@ int sqlite3_create_window_function( ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] ** might become a no-op if the function is used as term in an -** [expression index]. +** [expression index]. On the other hand, SQL functions that never invoke +** [sqlite3_result_subtype()] should avoid setting this property, as the +** purpose of this property is to disable certain optimizations that are +** incompatible with subtypes. **
    ** */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 -#define SQLITE_SUBTYPE 0x000100000 /* Deprecated name */ -#define SQLITE_VALUE_SUBTYPE 0x000100000 /* Use instead of SQLITE_SUBTYPE */ +#define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 #define SQLITE_RESULT_SUBTYPE 0x001000000 @@ -5800,6 +5794,13 @@ int sqlite3_value_encoding(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. +** +** Every [application-defined SQL function] that invoke this interface +** must include the [SQLITE_SUBTYPE] property in the text +** encoding argument when the function is [sqlite3_create_function|registered]. +** The sqlite3_value_subtype() can return an incorrect answer if it +** is invoked from within an application-defined SQL function that does +** not have the [SQLITE_SUBTYPE] property. */ unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -6219,6 +6220,14 @@ int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. +** +** Every [application-defined SQL function] that invokes this interface +** must include the [SQLITE_RESULT_SUBTYPE] property in its +** text encoding argument when the SQL function is +** [sqlite3_create_function|registered]. If the sqlite3_result_subtype() +** interface is invoked within an SQL function that does not have the +** SQLITE_RESULT_SUBTYPE property, then sqlite3_result_subtype() +** might fail to set the result subtype. */ void sqlite3_result_subtype(sqlite3_context*,unsigned int); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1a1e1268a4..35c4d403e6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2018,7 +2018,7 @@ struct FuncDestructor { #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ -/* SQLITE_VALUE_SUBTYPE 0x00100000 // Consumer of subtypes */ +/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ @@ -2117,7 +2117,7 @@ struct FuncDestructor { #define JFUNCTION(zName, nArg, bUseCache, bRS, bWS, iArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ - ((bRS)*SQLITE_VALUE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ + ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ @@ -4454,7 +4454,7 @@ struct Window { int regStartRowid; int regEndRowid; u8 bExprArgs; /* Defer evaluation of window function arguments - ** due to the SQLITE_VALUE_SUBTYPE flag */ + ** due to the SQLITE_SUBTYPE flag */ }; #ifndef SQLITE_OMIT_WINDOWFUNC diff --git a/src/window.c b/src/window.c index edbfb6c7e0..62df349fb3 100644 --- a/src/window.c +++ b/src/window.c @@ -1038,7 +1038,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; - if( pWin->pWFunc->funcFlags & SQLITE_VALUE_SUBTYPE ){ + if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; From b9050dcec70bb0767b7ac8419700b16365c338c5 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 9 Nov 2023 12:48:54 +0000 Subject: [PATCH 39/55] Add some notes about the JNI pointer-passing approach and convert a couple of potential NullPointerExceptions into appropriate C result codes. Clarify that invocation of undefined behaviour from the Java API does not (due to the addition of defensive code) mean the same thing as it does in C (e.g. no NULL pointer dereferences). FossilOrigin-Name: 19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8 --- ext/jni/src/c/sqlite3-jni.c | 15 +++++++-- ext/jni/src/c/sqlite3-jni.h | 4 +-- .../org/sqlite/jni/annotation/NotNull.java | 31 +++++++++++++------ ext/jni/src/org/sqlite/jni/capi/CApi.java | 10 ++++-- manifest | 18 +++++------ manifest.uuid | 2 +- 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 9384fb9d21..fafb2ab5fd 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -185,6 +185,8 @@ ** ** This use of intptr_t is the _only_ reason we require ** which, in turn, requires building with -std=c99 (or later). +** +** See also: the notes for LongPtrGet_T. */ #define S3JniCast_L2P(JLongAsPtr) (void*)((intptr_t)(JLongAsPtr)) #define S3JniCast_P2L(PTR) (jlong)((intptr_t)(PTR)) @@ -1493,6 +1495,15 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph, ** the C side, because it's reportedly significantly faster. The ** intptr_t part here is necessary for compatibility with (at least) ** ARM32. +** +** 2023-11-09: testing has not revealed any measurable performance +** difference between the approach of passing type T to C compared to +** passing pointer-to-T to C, and adding support for the latter +** everywhere requires sigificantly more code. As of this writing, the +** older/simpler approach is being applied except for (A) where the +** newer approach has already been applied and (B) hot-spot APIs where +** a difference of microseconds (i.e. below our testing measurement +** threshold) might add up. */ #define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr)) #define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,JLongAsPtr) @@ -4674,9 +4685,9 @@ S3JniApi(sqlite3_sql(),jstring,1sql)( } S3JniApi(sqlite3_step(),jint,1step)( - JniArgsEnvClass,jobject jStmt + JniArgsEnvClass, jlong jpStmt ){ - sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jStmt); + sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt); return pStmt ? (jint)sqlite3_step(pStmt) : (jint)SQLITE_MISUSE; } diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index f160b6453f..e655a71f63 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1872,10 +1872,10 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1status64 /* * Class: org_sqlite_jni_capi_CApi * Method: sqlite3_step - * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1step - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jlong); /* * Class: org_sqlite_jni_capi_CApi diff --git a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java index 3b4c1c7af1..57639fa0d9 100644 --- a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java +++ b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java @@ -18,12 +18,12 @@ package org.sqlite.jni.annotation; null or point to closed/finalized C-side resources.

    In the case of Java types which map directly to C struct types - (e.g. {@link org.sqlite.jni.sqlite3}, {@link - org.sqlite.jni.sqlite3_stmt}, and {@link - org.sqlite.jni.sqlite3_context}), a closed/finalized resource is - also considered to be null for purposes this annotation because the - C-side effect of passing such a handle is the same as if null is - passed.

    + (e.g. {@link org.sqlite.jni.capi.sqlite3}, {@link + org.sqlite.jni.capi.sqlite3_stmt}, and {@link + org.sqlite.jni.capi.sqlite3_context}), a closed/finalized resource + is also considered to be null for purposes this annotation because + the C-side effect of passing such a handle is the same as if null + is passed.

    When used in the context of Java interfaces which are called from the C APIs, this annotation communicates that the C API will @@ -31,12 +31,23 @@ package org.sqlite.jni.annotation;

    Passing a null, for this annotation's definition of null, for any parameter marked with this annoation specifically invokes - undefined behavior.

    + undefined behavior (see below).

    Passing 0 (i.e. C NULL) or a negative value for any long-type parameter marked with this annoation specifically invokes undefined - behavior. Such values are treated as C pointers in the JNI - layer.

    + behavior (see below). Such values are treated as C pointers in the + JNI layer.

    + +

    Undefined behaviour: the JNI build uses the {@code + SQLITE_ENABLE_API_ARMOR} build flag, meaning that the C code + invoked with invalid NULL pointers and the like will not invoke + undefined behavior in the conventional C sense, but may, for + example, return result codes which are not documented for the + affected APIs or may otherwise behave unpredictably. In no known + cases will such arguments result in C-level code dereferencing a + NULL pointer or accessing out-of-bounds (or otherwise invalid) + memory. In other words, they may cause unexpected behavior but + should never cause an outright crash or security issue.

    Note that the C-style API does not throw any exceptions on its own because it has a no-throw policy in order to retain its C-style @@ -48,7 +59,7 @@ package org.sqlite.jni.annotation; code.

    This annotation is solely for the use by the classes in the - org.sqlite package and subpackages, but is made public so that + org.sqlite.jni package and subpackages, but is made public so that javadoc will link to it from the annotated functions. It is not part of the public API and client-level code must not rely on it.

    diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 8e0cb8f4aa..c14772353d 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -1734,20 +1734,24 @@ public final class CApi { @NotNull OutputPointer.Int64 pHighwater, boolean reset ); - public static native int sqlite3_step(@NotNull sqlite3_stmt stmt); + private static native int sqlite3_step(@NotNull long ptrToStmt); + + public static int sqlite3_step(@NotNull sqlite3_stmt stmt){ + return null==stmt ? SQLITE_MISUSE : sqlite3_step(stmt.getNativePointer()); + } public static native boolean sqlite3_stmt_busy(@NotNull sqlite3_stmt stmt); private static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op); public static int sqlite3_stmt_explain(@NotNull sqlite3_stmt stmt, int op){ - return sqlite3_stmt_explain(stmt.getNativePointer(), op); + return null==stmt ? SQLITE_MISUSE : sqlite3_stmt_explain(stmt.getNativePointer(), op); } private static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt); public static int sqlite3_stmt_isexplain(@NotNull sqlite3_stmt stmt){ - return sqlite3_stmt_isexplain(stmt.getNativePointer()); + return null==stmt ? 0 : sqlite3_stmt_isexplain(stmt.getNativePointer()); } public static native boolean sqlite3_stmt_readonly(@NotNull sqlite3_stmt stmt); diff --git a/manifest b/manifest index f6390adef5..65ac65ba7a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Two\smore\sJNI\sbuild\sfixes\sfor\sWindows/MinGW,\sreported\sin\s[forum:4f949edc312d2a75|forum\spost\s4f949edc312d2a75]. -D 2023-11-09T12:01:02.729 +C Add\ssome\snotes\sabout\sthe\sJNI\spointer-passing\sapproach\sand\sconvert\sa\scouple\sof\spotential\sNullPointerExceptions\sinto\sappropriate\sC\sresult\scodes.\sClarify\sthat\sinvocation\sof\sundefined\sbehaviour\sfrom\sthe\sJava\sAPI\sdoes\snot\s(due\sto\sthe\saddition\sof\sdefensive\scode)\smean\sthe\ssame\sthing\sas\sit\sdoes\sin\sC\s(e.g.\sno\sNULL\spointer\sdereferences). +D 2023-11-09T12:48:54.107 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -241,9 +241,9 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile d984ea9c4e3536188f9d663120db8fb97b83329f4b8864bd88f75ebe581b8b8b F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 6b95974189d7cc394afbe15507050f1d174170a65be5a4dad201ab11f0a9777a -F ext/jni/src/c/sqlite3-jni.h 18925c56d6664fdec081c56daf3b2ffa0e0ff6b9b128b9f39b84862f34ba0601 -F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 +F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26 +F ext/jni/src/c/sqlite3-jni.h 489044eae9fc6c2d62c1621e41594adf7bfcd4049b514a202c4aa6fe5c1ef405 +F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 16a28138c3c25f33356193970644389ff8ebc0720499549653934b2529c8d1dd +F ext/jni/src/org/sqlite/jni/capi/CApi.java 2917e2c608ac52ebe30fbcde2b520c6ea3bc99e734619dfdedd072b8e956b84f F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -2139,8 +2139,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 1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0 -R 17c07891ab0f75a8281c2b918fd5c523 +P a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4 +R d00dc0a6ea6feccf2aee95fe4c483ba0 U stephan -Z 19240fed0f90b5e1367576a460d156b0 +Z 4aa2d438a8d23b9c44b1a48729f3cdde # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 300175f17c..7b8b377c39 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4 \ No newline at end of file +19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8 \ No newline at end of file From 6eb381ff4a2c430335f5eb6f43915456ef4cbadd Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 12:58:03 +0000 Subject: [PATCH 40/55] Add the SQLITE_STRICT_SUBTYPE compile-time option. This change reveals that the current SQLITE_RESULT_SUBTYPE design does not work unless we tag the ->> operator with SQLITE_RESULT_SUBTYPE. But that will disable an important optimization. FossilOrigin-Name: e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9 --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/sqlite.h.in | 6 ++++++ src/vdbeapi.c | 10 ++++++++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 50b7a2513d..b8e1b6dbb4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sreplace\sexpressions\sthat\sreturn\ssubtypes\swith\svalues\staken\sfrom\san\nindex. -D 2023-11-09T12:17:57.430 +C Add\sthe\sSQLITE_STRICT_SUBTYPE\scompile-time\soption.\s\sThis\schange\sreveals\sthat\nthe\scurrent\sSQLITE_RESULT_SUBTYPE\sdesign\sdoes\snot\swork\sunless\swe\stag\sthe\s->>\noperator\swith\sSQLITE_RESULT_SUBTYPE.\s\sBut\sthat\swill\sdisable\san\simportant\noptimization. +D 2023-11-09T12:58:03.925 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -726,7 +726,7 @@ F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f -F src/sqlite.h.in 8da45c84e79cde72c73fcb4260addcc7c00fac3bc6f5594b81a3792c1b196264 +F src/sqlite.h.in b6eac8ba5956af95269875a27273ab4c318d16ce4143f1d944962defce9accc6 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqliteInt.h cd171cba32c7a553e7623fbd82b68b36a1b6c81079ab963260777ea9b3abe4d9 @@ -797,7 +797,7 @@ F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 F src/vdbe.c 7034cf3eec0c905df753368efbcdd96377fca0245584e66766ec47a29fe468c8 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c -F src/vdbeapi.c db190d007bdf5b9165edeb12369f4c59a459f88fd652c1671c1238862e662cc3 +F src/vdbeapi.c 2fdec801f959512b4f752eaeb4bf926e2363f7f16b34675634eac059b6874279 F src/vdbeaux.c f3997b5956c8d97bd2fc3392db42caecddfa6549e9df82e0a7e5804653ca475a F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5 F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0 @@ -2139,9 +2139,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 563ad3be60d22c45f1c5b9a3e67738593f8b38f137147c56514166fbabf95365 e908b26a990929996b3c16f0429e8313cd8fcefe7c883c77f66ea69f4059d6e2 -R 9822cb01a0a25ade383ea6b744dcbd50 -T +closed e908b26a990929996b3c16f0429e8313cd8fcefe7c883c77f66ea69f4059d6e2 +P a35d13db09e32ee339f3983fe36b073714753ee3d39f577ae8d20596d7adc3eb +R 6425b1b4c4c82163cf87cfe5bb4306d2 U drh -Z 9cbc66987b5c47a4fc137a8fa57a64ca +Z 98ed3058dfd2554eb2316e0ec6804b54 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f5689a65a6..5aaf6a985d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a35d13db09e32ee339f3983fe36b073714753ee3d39f577ae8d20596d7adc3eb \ No newline at end of file +e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 09e6f47653..0932a2cb25 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6228,6 +6228,12 @@ int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** interface is invoked within an SQL function that does not have the ** SQLITE_RESULT_SUBTYPE property, then sqlite3_result_subtype() ** might fail to set the result subtype. +** +** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any +** SQL function that invokes the sqlite3_result_subtype() interface +** and that does not have the SQLITE_RESULT_SUBTYPE property will raise +** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 +** by default. */ void sqlite3_result_subtype(sqlite3_context*,unsigned int); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 6724035fd5..af717734e0 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -539,6 +539,16 @@ void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif +#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0 + if( (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 ){ + char zErr[200]; + sqlite3_snprintf(sizeof(zErr), zErr, + "misuse of sqlite3_result_subtype() by %s()", + pCtx->pFunc->zName); + sqlite3_result_error(pCtx, zErr, -1); + return; + } +#endif /* SQLITE_STRICT_SUBTYPE */ pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); pOut->eSubtype = eSubtype & 0xff; From 752722e8d1907522c1b4cb8e8c33edcbb14325fb Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 9 Nov 2023 13:00:33 +0000 Subject: [PATCH 41/55] A .class file build dependencies fix in the JNI build. FossilOrigin-Name: 8cc32915165efd7c261f008bb6fa4cc6581ee7bd73ea5da47513742b9e6d34e4 --- ext/jni/GNUmakefile | 4 +++- ext/jni/src/org/sqlite/jni/capi/CApi.java | 4 ++-- .../src/org/sqlite/jni/capi/sqlite3_blob.java | 1 - manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index dc93f49085..25dc1596a4 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -112,6 +112,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\ WindowFunction.java \ XDestroyCallback.java \ sqlite3.java \ + sqlite3_blob.java \ sqlite3_context.java \ sqlite3_stmt.java \ sqlite3_value.java \ @@ -162,12 +163,13 @@ endif CLASS_FILES := define CLASSFILE_DEPS all: $(1).class +$(1).class: $(1).java CLASS_FILES += $(1).class endef $(foreach B,$(basename \ $(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.tester)),\ $(eval $(call CLASSFILE_DEPS,$(B)))) -$(CLASS_FILES): $(JAVA_FILES) $(MAKEFILE) +$(CLASS_FILES): $(MAKEFILE) $(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES) #.PHONY: classfiles diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index c14772353d..1f99b8e4a8 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -1772,7 +1772,7 @@ public final class CApi { signature is the public-facing one. */ private static native int sqlite3_strglob( - @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8 + @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8 ); public static int sqlite3_strglob( @@ -1786,7 +1786,7 @@ public final class CApi { The LIKE counterpart of the private sqlite3_strglob() method. */ private static native int sqlite3_strlike( - @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8, + @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8, int escChar ); diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java index 4bca3363ff..bdc0200af4 100644 --- a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java +++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java @@ -27,5 +27,4 @@ public final class sqlite3_blob extends NativePointerHolder @Override public void close(){ CApi.sqlite3_blob_close(this); } - } diff --git a/manifest b/manifest index 65ac65ba7a..306eb3b70f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssome\snotes\sabout\sthe\sJNI\spointer-passing\sapproach\sand\sconvert\sa\scouple\sof\spotential\sNullPointerExceptions\sinto\sappropriate\sC\sresult\scodes.\sClarify\sthat\sinvocation\sof\sundefined\sbehaviour\sfrom\sthe\sJava\sAPI\sdoes\snot\s(due\sto\sthe\saddition\sof\sdefensive\scode)\smean\sthe\ssame\sthing\sas\sit\sdoes\sin\sC\s(e.g.\sno\sNULL\spointer\sdereferences). -D 2023-11-09T12:48:54.107 +C A\s.class\sfile\sbuild\sdependencies\sfix\sin\sthe\sJNI\sbuild. +D 2023-11-09T13:00:33.039 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -238,7 +238,7 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 -F ext/jni/GNUmakefile d984ea9c4e3536188f9d663120db8fb97b83329f4b8864bd88f75ebe581b8b8b +F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9cd020d4 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26 @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 2917e2c608ac52ebe30fbcde2b520c6ea3bc99e734619dfdedd072b8e956b84f +F ext/jni/src/org/sqlite/jni/capi/CApi.java ca7b783c24b40ceac6f20ef51636682577230e463ccc91ed83a0645ba1a745ba F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -278,7 +278,7 @@ F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba90943 F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e F ext/jni/src/org/sqlite/jni/capi/sqlite3.java c6a5c555d163d76663534f2b2cce7cab15325b9852d0f58c6688a85e73ae52f0 F ext/jni/src/org/sqlite/jni/capi/sqlite3_backup.java 6742b431cd4d77e8000c1f92ec66265a58414c86bf3b0b5fbcb1164e08477227 -F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java e8c799ed89a7725ba779ff7d4b1d941c5aaae1b1c3888a68a10ee9cca5c71e7d +F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java 59e26ca5254cd4771f467237bcfe2d8deed30a77152fabcd4574fd406c301d63 F ext/jni/src/org/sqlite/jni/capi/sqlite3_context.java f0ef982009c335c4393ffcb68051809ca1711e4f47bcb8d1d46952f22c01bc22 F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java 293b5fa7d5b5724c87de544654aca1103d76f3092bc2c8f4360102a65ba25dff F ext/jni/src/org/sqlite/jni/capi/sqlite3_value.java e1d62a257c13504b46d39d5c21c49cf157ad73fda00cc5f34c931aa008c37049 @@ -2139,8 +2139,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 a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4 -R d00dc0a6ea6feccf2aee95fe4c483ba0 +P 19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8 +R cd252fb625d9fc6706ab257c76ca795a U stephan -Z 4aa2d438a8d23b9c44b1a48729f3cdde +Z de48d509d9df78c4a1c1c2968a76e682 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7b8b377c39..922f6f0dc8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8 \ No newline at end of file +8cc32915165efd7c261f008bb6fa4cc6581ee7bd73ea5da47513742b9e6d34e4 \ No newline at end of file From b10c3d32e05d88288e106681d4e08d7ffa719dd2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 15:01:56 +0000 Subject: [PATCH 42/55] Fixes: (1) In the ->> function, instead of setting a subtype and clearing it, do not set it in the first place, as doing the set would trigger an error under SQLITE_STRICT_SUBTYPE. (2) Allow the SQLITE_STRICT_SUBTYPE through the property filter on sqlite3_create_function(). FossilOrigin-Name: 6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/json.c | 33 +++++++++++++++++---------------- src/main.c | 2 +- src/vdbeapi.c | 4 +++- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index b8e1b6dbb4..23f1a35a4e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_STRICT_SUBTYPE\scompile-time\soption.\s\sThis\schange\sreveals\sthat\nthe\scurrent\sSQLITE_RESULT_SUBTYPE\sdesign\sdoes\snot\swork\sunless\swe\stag\sthe\s->>\noperator\swith\sSQLITE_RESULT_SUBTYPE.\s\sBut\sthat\swill\sdisable\san\simportant\noptimization. -D 2023-11-09T12:58:03.925 +C Fixes:\s\s(1)\sIn\sthe\s->>\sfunction,\sinstead\sof\ssetting\sa\ssubtype\sand\sclearing\sit,\ndo\snot\sset\sit\sin\sthe\sfirst\splace,\sas\sdoing\sthe\sset\swould\strigger\san\serror\nunder\sSQLITE_STRICT_SUBTYPE.\s\s(2)\sAllow\sthe\sSQLITE_STRICT_SUBTYPE\sthrough\nthe\sproperty\sfilter\son\ssqlite3_create_function(). +D 2023-11-09T15:01:56.971 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -684,10 +684,10 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c bf117324d2efff47b392c29f7d3e611a7508933b91491c7ad349101e6d5f5e05 +F src/json.c afbda7533099b951f6e7fbe5c050d12fb7b736bf377b263f824f64bbc6af7f0c F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 -F src/main.c e1bc8864834697503d370d94613be945d05ca1c5ebdda43e7d5c8ee8c48d433c +F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9 F src/malloc.c f016922435dc7d1f1f5083a03338a3e91f8c67ce2c5bdcfa4cdef62e612f5fcc F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 @@ -797,7 +797,7 @@ F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 F src/vdbe.c 7034cf3eec0c905df753368efbcdd96377fca0245584e66766ec47a29fe468c8 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c -F src/vdbeapi.c 2fdec801f959512b4f752eaeb4bf926e2363f7f16b34675634eac059b6874279 +F src/vdbeapi.c b07df805110dc6e81f2a3f9cd4e83f56ea523277a59bcec489a12b740c1079e7 F src/vdbeaux.c f3997b5956c8d97bd2fc3392db42caecddfa6549e9df82e0a7e5804653ca475a F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5 F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0 @@ -2139,8 +2139,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 a35d13db09e32ee339f3983fe36b073714753ee3d39f577ae8d20596d7adc3eb -R 6425b1b4c4c82163cf87cfe5bb4306d2 +P e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9 +R e019c72939d4c624411f804ee942841e U drh -Z 98ed3058dfd2554eb2316e0ec6804b54 +Z 80a4b0d4e614ee4844ff727ed0551cab # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5aaf6a985d..d8dd13b107 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9 \ No newline at end of file +6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc \ No newline at end of file diff --git a/src/json.c b/src/json.c index 132a274cd3..864504386f 100644 --- a/src/json.c +++ b/src/json.c @@ -833,7 +833,8 @@ static void jsonReturnJson( JsonParse *pParse, /* The complete JSON */ JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ - int bGenerateAlt /* Also store the rendered text in zAlt */ + int bGenerateAlt, /* Also store the rendered text in zAlt */ + int omitSubtype /* Do not call sqlite3_result_subtype() */ ){ JsonString s; if( pParse->oom ){ @@ -848,7 +849,7 @@ static void jsonReturnJson( pParse->nAlt = s.nUsed; } jsonResult(&s); - sqlite3_result_subtype(pCtx, JSON_SUBTYPE); + if( !omitSubtype ) sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } } @@ -889,7 +890,8 @@ static u32 jsonHexToInt4(const char *z){ static void jsonReturn( JsonParse *pParse, /* Complete JSON parse tree */ JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx /* Return value for this function */ + sqlite3_context *pCtx, /* Return value for this function */ + int omitSubtype /* Do not call sqlite3_result_subtype() */ ){ switch( pNode->eType ){ default: { @@ -1035,7 +1037,7 @@ static void jsonReturn( } case JSON_ARRAY: case JSON_OBJECT: { - jsonReturnJson(pParse, pNode, pCtx, 0); + jsonReturnJson(pParse, pNode, pCtx, 0, omitSubtype); break; } } @@ -2387,7 +2389,7 @@ static void jsonParseFunc( printf("iSubst = %u\n", p->iSubst); printf("iHold = %u\n", p->iHold); jsonDebugPrintNodeEntries(p->aNode, p->nNode); - jsonReturnJson(p, p->aNode, ctx, 1); + jsonReturnJson(p, p->aNode, ctx, 1, 0); } /* @@ -2573,15 +2575,14 @@ static void jsonExtractFunc( } if( pNode ){ if( flags & JSON_JSON ){ - jsonReturnJson(p, pNode, ctx, 0); + jsonReturnJson(p, pNode, ctx, 0, 0); }else{ - jsonReturn(p, pNode, ctx); - sqlite3_result_subtype(ctx, 0); + jsonReturn(p, pNode, ctx, 1); } } }else{ pNode = jsonLookup(p, zPath, 0, ctx); - if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx); + if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx, 0); } }else{ /* Two or more PATH arguments results in a JSON array with each @@ -2707,7 +2708,7 @@ static void jsonPatchFunc( if( pResult && pX->oom==0 ){ jsonDebugPrintParse(pX); jsonDebugPrintNode(pResult); - jsonReturnJson(pX, pResult, ctx, 0); + jsonReturnJson(pX, pResult, ctx, 0, 0); }else{ sqlite3_result_error_nomem(ctx); } @@ -2786,7 +2787,7 @@ static void jsonRemoveFunc( } } if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){ - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); } remove_done: jsonDebugPrintParse(p); @@ -2915,7 +2916,7 @@ static void jsonReplaceFunc( jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); } } - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); replace_err: jsonDebugPrintParse(pParse); jsonParseFree(pParse); @@ -2969,7 +2970,7 @@ static void jsonSetFunc( } } jsonDebugPrintParse(pParse); - jsonReturnJson(pParse, pParse->aNode, ctx, 1); + jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); jsonSetDone: jsonParseFree(pParse); } @@ -3484,7 +3485,7 @@ static int jsonEachColumn( case JEACH_KEY: { if( p->i==0 ) break; if( p->eType==JSON_OBJECT ){ - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); }else if( p->eType==JSON_ARRAY ){ u32 iKey; if( p->bRecursive ){ @@ -3500,7 +3501,7 @@ static int jsonEachColumn( } case JEACH_VALUE: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); break; } case JEACH_TYPE: { @@ -3511,7 +3512,7 @@ static int jsonEachColumn( case JEACH_ATOM: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->eType>=JSON_ARRAY ) break; - jsonReturn(&p->sParse, pThis, ctx); + jsonReturn(&p->sParse, pThis, ctx, 0); break; } case JEACH_ID: { diff --git a/src/main.c b/src/main.c index fbe00f5fa9..6acfdc325d 100644 --- a/src/main.c +++ b/src/main.c @@ -1914,7 +1914,7 @@ int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But diff --git a/src/vdbeapi.c b/src/vdbeapi.c index af717734e0..570cb3d8b6 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -540,7 +540,9 @@ void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ if( pCtx==0 ) return; #endif #if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0 - if( (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 ){ + if( pCtx->pFunc!=0 + && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 + ){ char zErr[200]; sqlite3_snprintf(sizeof(zErr), zErr, "misuse of sqlite3_result_subtype() by %s()", From cb1f190ed2fd7ee0f0ea788a32d06bf843b4b177 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 16:52:44 +0000 Subject: [PATCH 43/55] Futher documentation refinements. FossilOrigin-Name: 311c2eba93097bbecfa286bbeaff9bd6fc75a238e20cd2b6f834e594032d8c59 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 29 ++++++++++++++++------------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 23f1a35a4e..f7930ccff9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes:\s\s(1)\sIn\sthe\s->>\sfunction,\sinstead\sof\ssetting\sa\ssubtype\sand\sclearing\sit,\ndo\snot\sset\sit\sin\sthe\sfirst\splace,\sas\sdoing\sthe\sset\swould\strigger\san\serror\nunder\sSQLITE_STRICT_SUBTYPE.\s\s(2)\sAllow\sthe\sSQLITE_STRICT_SUBTYPE\sthrough\nthe\sproperty\sfilter\son\ssqlite3_create_function(). -D 2023-11-09T15:01:56.971 +C Futher\sdocumentation\srefinements. +D 2023-11-09T16:52:44.766 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -726,7 +726,7 @@ F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f -F src/sqlite.h.in b6eac8ba5956af95269875a27273ab4c318d16ce4143f1d944962defce9accc6 +F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqliteInt.h cd171cba32c7a553e7623fbd82b68b36a1b6c81079ab963260777ea9b3abe4d9 @@ -2139,8 +2139,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 e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9 -R e019c72939d4c624411f804ee942841e +P 6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc +R d70a69270dd45a660decb50b1e7c2d52 U drh -Z 80a4b0d4e614ee4844ff727ed0551cab +Z 8b58d9d66b776c4e0e8bd09f1958be56 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d8dd13b107..5faebb1c2d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc \ No newline at end of file +311c2eba93097bbecfa286bbeaff9bd6fc75a238e20cd2b6f834e594032d8c59 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0932a2cb25..53c037c3ba 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5573,11 +5573,15 @@ int sqlite3_create_window_function( ** ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** Every function that invokes [sqlite3_value_subtype()] should have this -** property. If it does not, then the query planner might generate -** incorrect code for queries that use that function. +** This flag instructs SQLite to omit some corner-case optimizations that +** might disrupt the operation of the [sqlite3_value_subtype()] function, +** causing it to return zero rather than the correct subtype(). +** SQL functions that invokes [sqlite3_value_subtype()] should have this +** property. If the SQLITE_SUBTYPE property is omitted, then the return +** value from [sqlite3_value_subtype()] might sometimes be zero even though +** a non-zero subtype was specified by the function argument expression. ** ** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    ** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call @@ -5796,11 +5800,10 @@ int sqlite3_value_encoding(sqlite3_value*); ** routine to set the subtype for the return value of an SQL function. ** ** Every [application-defined SQL function] that invoke this interface -** must include the [SQLITE_SUBTYPE] property in the text +** should include the [SQLITE_SUBTYPE] property in the text ** encoding argument when the function is [sqlite3_create_function|registered]. -** The sqlite3_value_subtype() can return an incorrect answer if it -** is invoked from within an application-defined SQL function that does -** not have the [SQLITE_SUBTYPE] property. +** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() +** might return zero instead of the upstream subtype in some corner cases. */ unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -6222,12 +6225,12 @@ int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** in future releases of SQLite. ** ** Every [application-defined SQL function] that invokes this interface -** must include the [SQLITE_RESULT_SUBTYPE] property in its +** should include the [SQLITE_RESULT_SUBTYPE] property in its ** text encoding argument when the SQL function is -** [sqlite3_create_function|registered]. If the sqlite3_result_subtype() -** interface is invoked within an SQL function that does not have the -** SQLITE_RESULT_SUBTYPE property, then sqlite3_result_subtype() -** might fail to set the result subtype. +** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] +** property is omitted from the function that invokes sqlite3_result_subtype(), +** then in some cases the sqlite3_result_subtype() might fail to set +** the result subtype. ** ** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any ** SQL function that invokes the sqlite3_result_subtype() interface From beb06e6b0a17b732ca0ab7e416891175eb87d3af Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 9 Nov 2023 17:26:39 +0000 Subject: [PATCH 44/55] Put an ALWAYS on an true branch. FossilOrigin-Name: 1e039b6eb59c0001a9efdd2f9928a34d4e9e01972ee76aa04a1279369dc03840 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f7930ccff9..bf13040ece 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Futher\sdocumentation\srefinements. -D 2023-11-09T16:52:44.766 +C Put\san\sALWAYS\son\san\strue\sbranch. +D 2023-11-09T17:26:39.395 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -809,7 +809,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 8718d58065745a4b7203a6b5d7c77b00d67eaf31a66d37c54a00f47c0cd23ac5 +F src/where.c d6ac0f598e725412af5b4484fe98187a129f3c8778c7dbc18ac7477294e190ca F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 @@ -2139,8 +2139,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 6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc -R d70a69270dd45a660decb50b1e7c2d52 +P 311c2eba93097bbecfa286bbeaff9bd6fc75a238e20cd2b6f834e594032d8c59 +R 017a5657e59f3d0e3637d7716ee24315 U drh -Z 8b58d9d66b776c4e0e8bd09f1958be56 +Z a5d8bd3105f63db4fe25f071664830bd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5faebb1c2d..fc5a44f74d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -311c2eba93097bbecfa286bbeaff9bd6fc75a238e20cd2b6f834e594032d8c59 \ No newline at end of file +1e039b6eb59c0001a9efdd2f9928a34d4e9e01972ee76aa04a1279369dc03840 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 448fe27c11..555bd6a349 100644 --- a/src/where.c +++ b/src/where.c @@ -5818,7 +5818,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( FuncDef *pDef; sqlite3 *db = pParse->db; assert( ExprUseXList(pExpr) ); - n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; + n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ continue; From 2009a5acba967eab68304cdb8feeb340f5a45782 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 9 Nov 2023 17:28:31 +0000 Subject: [PATCH 45/55] Fix compilation issue seen with MSVC. FossilOrigin-Name: 0dfe790d8118ff1bacc9e7c97d4f8ff9e5789f6cda8ec6fd981ea38b4da3905d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 4 ++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 306eb3b70f..184cdce6c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\s.class\sfile\sbuild\sdependencies\sfix\sin\sthe\sJNI\sbuild. -D 2023-11-09T13:00:33.039 +C Fix\scompilation\sissue\sseen\swith\sMSVC. +D 2023-11-09T17:28:31.730 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -725,7 +725,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 -F src/shell.c.in 7312c571ebf518fc8927bbb5aeb4fa67e5b0dfb2adae4258dcd1ccae42c11e1f +F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140 F src/sqlite.h.in a0fce680a40fe81b13eae3749d001134d9fe0a43aecc09a8986520d5119acfcd F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 @@ -2139,8 +2139,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 19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8 -R cd252fb625d9fc6706ab257c76ca795a -U stephan -Z de48d509d9df78c4a1c1c2968a76e682 +P 8cc32915165efd7c261f008bb6fa4cc6581ee7bd73ea5da47513742b9e6d34e4 +R 8854825d1f1736b898c17995440cc740 +U mistachkin +Z 0431c54643f1f1f0b5b6ac8fca652889 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 922f6f0dc8..1bd2f05fab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8cc32915165efd7c261f008bb6fa4cc6581ee7bd73ea5da47513742b9e6d34e4 \ No newline at end of file +0dfe790d8118ff1bacc9e7c97d4f8ff9e5789f6cda8ec6fd981ea38b4da3905d \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 8d201bbbda..0e0dbd36c7 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1311,7 +1311,11 @@ static void shellDtostr( char z[400]; if( n<1 ) n = 1; if( n>350 ) n = 350; +#if defined(_MSC_VER) + _snprintf(z, sizeof(z)-2, "%#+.*e", n, r); +#else snprintf(z, sizeof(z)-1, "%#+.*e", n, r); +#endif sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); } From 6db0b11e078f4b651f0cf00f845f3d77700c1a3a Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 9 Nov 2023 17:53:44 +0000 Subject: [PATCH 46/55] Expose SQLITE_RESULT_SUBTYPE to wasm. FossilOrigin-Name: 6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749 --- ext/wasm/api/sqlite3-wasm.c | 1 + manifest | 15 +++++++-------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index 18d27bdf0c..38e235d1aa 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -901,6 +901,7 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_DETERMINISTIC); DefInt(SQLITE_DIRECTONLY); DefInt(SQLITE_INNOCUOUS); + DefInt(SQLITE_RESULT_SUBTYPE); } _DefGroup; DefGroup(version) { diff --git a/manifest b/manifest index 29fbba28e4..ec49407a50 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_RESULT_SUBTYPE\sflag\sfor\sapplication-defined\sfunctions.\s\sAdd\nthe\s-DSQLITE_STRICT_SUBTYPE=1\scompile-time\soption\sthat\sraises\san\serror\sif\nany\sfunction\sinvokes\ssqlite3_result_subtype()\swithout\sthe\sSQLITE_RESULT_SUBTYPE\nflag.\s\sSQLITE_RESULT_SUBTYPE\sprevents\san\sindexed\svalue\sof\sthat\sfunction\sfrom\nbeing\sused\sto\sreplace\san\sequivalent\sexpression,\ssince\sthe\sindexed\sexpression\ndoes\snot\scarry\sthe\ssubtype.\s\sFix\sfor\sthe\sproblem\sdescribed\sat\n[forum:/forumpost/68d284c86b082c3e|forum\spost\s68d284c86b082c3e]. -D 2023-11-09T17:36:37.321 +C Expose\sSQLITE_RESULT_SUBTYPE\sto\swasm. +D 2023-11-09T17:53:44.655 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -591,7 +591,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256 F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 595953994aa3ae2287c889c4da39ab3d6f17b6461ecf4bec334b7a3faafddb02 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 46c4afa6c50d7369252c104f274ad977a97e91ccfafc38b400fe36e90bdda88e -F ext/wasm/api/sqlite3-wasm.c 038de1b6d40b2cc0f41a143a0451db60b2a6f1b5bc06de67da255c54ea1661b7 +F ext/wasm/api/sqlite3-wasm.c d1b6c7264e28f6825d970321d589c2e35ecfe778dea28252a165d2bd1a407a83 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f F ext/wasm/api/sqlite3-worker1.c-pp.js a541112aa51e16705f13a99bb943c64efe178aa28c86704a955f8fd9afe4ba37 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 @@ -2139,9 +2139,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 0dfe790d8118ff1bacc9e7c97d4f8ff9e5789f6cda8ec6fd981ea38b4da3905d 1e039b6eb59c0001a9efdd2f9928a34d4e9e01972ee76aa04a1279369dc03840 -R 43a4ac60d204fdc6ba9347ecb0c1fc0b -T +closed 1e039b6eb59c0001a9efdd2f9928a34d4e9e01972ee76aa04a1279369dc03840 -U drh -Z b1e7abc144feb80d39f106f6377a94b7 +P ba789a7804ab96d81b15d6ef6fed1f802fa69db47cf91d368933e55289fa1d6e +R 41023b666496061ded61da7b2b1efc39 +U stephan +Z edb2bf000d7c6b4a58ab9adf26347d73 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 86ff0f4395..35c2e08c33 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba789a7804ab96d81b15d6ef6fed1f802fa69db47cf91d368933e55289fa1d6e \ No newline at end of file +6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749 \ No newline at end of file From af65e7d21f6d54474e60f8dc65db879bd400fb81 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 10 Nov 2023 14:15:07 +0000 Subject: [PATCH 47/55] Expose SQLITE_RESULT_SUBTYPE to JNI. FossilOrigin-Name: 3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197 --- ext/jni/src/c/sqlite3-jni.h | 2 ++ ext/jni/src/org/sqlite/jni/capi/CApi.java | 7 ++++--- .../src/org/sqlite/jni/wrapper1/SqlFunction.java | 8 ++------ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index e655a71f63..7201372640 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -705,6 +705,8 @@ extern "C" { #define org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC 2048L #undef org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY #define org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY 524288L +#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE +#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L #undef org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS #define org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS 2097152L #undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 1f99b8e4a8..9b51bcf926 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -2445,9 +2445,10 @@ public final class CApi { public static final int SQLITE_TXN_WRITE = 2; // udf flags - public static final int SQLITE_DETERMINISTIC = 0x000000800; - public static final int SQLITE_DIRECTONLY = 0x000080000; - public static final int SQLITE_INNOCUOUS = 0x000200000; + public static final int SQLITE_DETERMINISTIC = 0x000000800; + public static final int SQLITE_DIRECTONLY = 0x000080000; + public static final int SQLITE_RESULT_SUBTYPE = 0x001000000; + public static final int SQLITE_INNOCUOUS = 0x000200000; // virtual tables public static final int SQLITE_INDEX_SCAN_UNIQUE = 1; diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index b3317029c7..6d583aaa48 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -25,13 +25,9 @@ public interface SqlFunction { public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC; public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS; public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY; + public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE; public static final int UTF8 = CApi.SQLITE_UTF8; public static final int UTF16 = CApi.SQLITE_UTF16; - // /** - // For Window functions only and is not currently bound because - // doing so may require exposing sqlite3_value for effective use. - // */ - // public static final int SUBTYPE = CApi.SQLITE_SUBTYPE; /** The Arguments type is an abstraction on top of the lower-level @@ -167,7 +163,7 @@ public interface SqlFunction { } /** - Wrapper for a single SqlFunction argument. Primarily intended + Represents a single SqlFunction argument. Primarily intended for use with the Arguments class's Iterable interface. */ public final static class Arg { diff --git a/manifest b/manifest index ec49407a50..ba395a8b8d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\sSQLITE_RESULT_SUBTYPE\sto\swasm. -D 2023-11-09T17:53:44.655 +C Expose\sSQLITE_RESULT_SUBTYPE\sto\sJNI. +D 2023-11-10T14:15:07.897 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -242,7 +242,7 @@ F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9c F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26 -F ext/jni/src/c/sqlite3-jni.h 489044eae9fc6c2d62c1621e41594adf7bfcd4049b514a202c4aa6fe5c1ef405 +F ext/jni/src/c/sqlite3-jni.h a69394f018b40135d4198d0d6553d93dcfc7b76d2256877aaa7d12f4fbd5d218 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java ca7b783c24b40ceac6f20ef51636682577230e463ccc91ed83a0645ba1a745ba +F ext/jni/src/org/sqlite/jni/capi/CApi.java cd99604b6cb2fc5f1bb3c715afc05059f8748aba34a0edae21f9ed7b963cbdbb F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -295,7 +295,7 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ad F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 -F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7 +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java cf01f04548860e56d484e175976e10d145621b0c7c5119dfa271e8acf2f83a0e F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b @@ -2139,8 +2139,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 ba789a7804ab96d81b15d6ef6fed1f802fa69db47cf91d368933e55289fa1d6e -R 41023b666496061ded61da7b2b1efc39 +P 6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749 +R 90e12dd1bb83d03b6e6ef1578e525a93 U stephan -Z edb2bf000d7c6b4a58ab9adf26347d73 +Z b0d483f5215eeb51133ba8f1f724a33e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 35c2e08c33..e143455a4b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749 \ No newline at end of file +3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197 \ No newline at end of file From 828a00c287fc739edbc1a9864caf823f085860ec Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 10 Nov 2023 15:00:11 +0000 Subject: [PATCH 48/55] Expose the missing SQLITE_SUBTYPE to JNI. FossilOrigin-Name: 0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271 --- ext/jni/src/c/sqlite3-jni.h | 6 ++++-- ext/jni/src/org/sqlite/jni/capi/CApi.java | 3 ++- .../src/org/sqlite/jni/wrapper1/SqlFunction.java | 1 + manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 7201372640..51d49bba3c 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -705,10 +705,12 @@ extern "C" { #define org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC 2048L #undef org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY #define org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY 524288L -#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE -#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L +#undef org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE +#define org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE 1048576L #undef org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS #define org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS 2097152L +#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE +#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L #undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE #define org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE 1L #undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_EQ diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 9b51bcf926..07ca851ce5 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -2447,8 +2447,9 @@ public final class CApi { // udf flags public static final int SQLITE_DETERMINISTIC = 0x000000800; public static final int SQLITE_DIRECTONLY = 0x000080000; - public static final int SQLITE_RESULT_SUBTYPE = 0x001000000; + public static final int SQLITE_SUBTYPE = 0x000100000; public static final int SQLITE_INNOCUOUS = 0x000200000; + public static final int SQLITE_RESULT_SUBTYPE = 0x001000000; // virtual tables public static final int SQLITE_INDEX_SCAN_UNIQUE = 1; diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index 6d583aaa48..dcfc2ebebd 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -25,6 +25,7 @@ public interface SqlFunction { public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC; public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS; public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY; + public static final int SUBTYPE = CApi.SQLITE_SUBTYPE; public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE; public static final int UTF8 = CApi.SQLITE_UTF8; public static final int UTF16 = CApi.SQLITE_UTF16; diff --git a/manifest b/manifest index ba395a8b8d..2efc6960bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\sSQLITE_RESULT_SUBTYPE\sto\sJNI. -D 2023-11-10T14:15:07.897 +C Expose\sthe\smissing\sSQLITE_SUBTYPE\sto\sJNI. +D 2023-11-10T15:00:11.915 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -242,7 +242,7 @@ F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9c F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26 -F ext/jni/src/c/sqlite3-jni.h a69394f018b40135d4198d0d6553d93dcfc7b76d2256877aaa7d12f4fbd5d218 +F ext/jni/src/c/sqlite3-jni.h 891444578550a7aa69fe5e0dedb3e6dedad752501ba99801f17797be51796934 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java cd99604b6cb2fc5f1bb3c715afc05059f8748aba34a0edae21f9ed7b963cbdbb +F ext/jni/src/org/sqlite/jni/capi/CApi.java 92d443b08175c798e132a312f71b1a42140c60d473d35c149e3d95a45b6550f3 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -295,7 +295,7 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ad F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 -F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java cf01f04548860e56d484e175976e10d145621b0c7c5119dfa271e8acf2f83a0e +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b @@ -2139,8 +2139,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 6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749 -R 90e12dd1bb83d03b6e6ef1578e525a93 +P 3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197 +R 1f0c514b861aa02e5ce12be54a134415 U stephan -Z b0d483f5215eeb51133ba8f1f724a33e +Z a3fd8bb69210abdca1305b9c9a0a5e7d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e143455a4b..214f2b3b2a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197 \ No newline at end of file +0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271 \ No newline at end of file From 9d60c3c256feae4d48d833c4eafcb83d8da0c695 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 10 Nov 2023 15:00:26 +0000 Subject: [PATCH 49/55] Expose the missing SQLITE_SUBTYPE to wasm. FossilOrigin-Name: ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739 --- ext/wasm/api/sqlite3-wasm.c | 3 ++- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c index 38e235d1aa..300307e5ea 100644 --- a/ext/wasm/api/sqlite3-wasm.c +++ b/ext/wasm/api/sqlite3-wasm.c @@ -877,7 +877,7 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_STMTSTATUS_FILTER_HIT); DefInt(SQLITE_STMTSTATUS_MEMUSED); } _DefGroup; - + DefGroup(syncFlags) { DefInt(SQLITE_SYNC_NORMAL); DefInt(SQLITE_SYNC_FULL); @@ -901,6 +901,7 @@ const char * sqlite3_wasm_enum_json(void){ DefInt(SQLITE_DETERMINISTIC); DefInt(SQLITE_DIRECTONLY); DefInt(SQLITE_INNOCUOUS); + DefInt(SQLITE_SUBTYPE); DefInt(SQLITE_RESULT_SUBTYPE); } _DefGroup; diff --git a/manifest b/manifest index 2efc6960bd..1dba8fccae 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\sthe\smissing\sSQLITE_SUBTYPE\sto\sJNI. -D 2023-11-10T15:00:11.915 +C Expose\sthe\smissing\sSQLITE_SUBTYPE\sto\swasm. +D 2023-11-10T15:00:26.011 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -591,7 +591,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256 F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 595953994aa3ae2287c889c4da39ab3d6f17b6461ecf4bec334b7a3faafddb02 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 46c4afa6c50d7369252c104f274ad977a97e91ccfafc38b400fe36e90bdda88e -F ext/wasm/api/sqlite3-wasm.c d1b6c7264e28f6825d970321d589c2e35ecfe778dea28252a165d2bd1a407a83 +F ext/wasm/api/sqlite3-wasm.c d0e09eb5ed3743c00294e30019e591c3aa150572ae7ffe8a8994568a7377589f F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f F ext/wasm/api/sqlite3-worker1.c-pp.js a541112aa51e16705f13a99bb943c64efe178aa28c86704a955f8fd9afe4ba37 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 @@ -2139,8 +2139,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 3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197 -R 1f0c514b861aa02e5ce12be54a134415 +P 0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271 +R 38810c4503b5945c0ad84d8e7829e79f U stephan -Z a3fd8bb69210abdca1305b9c9a0a5e7d +Z 7eb27f62c37852223a1d4389da1ef1c0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 214f2b3b2a..c5efbb3408 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271 \ No newline at end of file +ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739 \ No newline at end of file From 0eed27d38bdd23c596f46d24dd81be9af470dcd6 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 10 Nov 2023 15:03:18 +0000 Subject: [PATCH 50/55] Fix an obscure problem with the join-strength-reduction optimization that could occur when mixing LEFT and RIGHT joins in the same query. [forum:/forumpost/7f74ce0bee|Forum post 7f74ce0bee]. FossilOrigin-Name: 530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/select.c | 5 ++--- test/joinH.test | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 1dba8fccae..853509f8ea 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expose\sthe\smissing\sSQLITE_SUBTYPE\sto\swasm. -D 2023-11-10T15:00:26.011 +C Fix\san\sobscure\sproblem\swith\sthe\sjoin-strength-reduction\soptimization\sthat\scould\soccur\swhen\smixing\sLEFT\sand\sRIGHT\sjoins\sin\sthe\ssame\squery.\s[forum:/forumpost/7f74ce0bee|Forum\spost\s7f74ce0bee]. +D 2023-11-10T15:03:18.325 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -724,7 +724,7 @@ F src/printf.c 9da63b9ae1c14789bcae12840f5d800fd9302500cd2d62733fac77f0041b4750 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c a19daa26e95f7245106a31f288b2f50c72d1f2cc156703f04c8c91450e111515 +F src/select.c 47797c57c5ee2ad183b34a2e5d643ec7519366686bbe44a9a81df9fe304f28a7 F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140 F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1309,7 +1309,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2 F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28 F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 -F test/joinH.test 84198ea42bf78b79fe399c0567218cd6df36c50c6dd27d9c4aab221acaad929e +F test/joinH.test c4301c738b05b845f273b0d94de74e953626d809dc945352909aedb199b42e5f F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -2139,8 +2139,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 0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271 -R 38810c4503b5945c0ad84d8e7829e79f -U stephan -Z 7eb27f62c37852223a1d4389da1ef1c0 +P ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739 +R a50d2c9cbe89dc0abaae6ac9eaaaf01b +U dan +Z c2b696ca5d071695417bed8717dba32c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c5efbb3408..e7c169124b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739 \ No newline at end of file +530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 7a79385e0b..c2685b370e 100644 --- a/src/select.c +++ b/src/select.c @@ -7397,6 +7397,7 @@ int sqlite3Select( TREETRACE(0x1000,pParse,p, ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); + unsetJoinExpr(p->pWhere, pItem->iCursor, 0); } } if( pItem->fg.jointype & JT_LTORJ ){ @@ -7411,6 +7412,7 @@ int sqlite3Select( TREETRACE(0x1000,pParse,p, ("RIGHT-JOIN simplifies to JOIN on term %d\n",j)); pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER); + unsetJoinExpr(p->pWhere, pI2->iCursor, 1); } } } @@ -7419,9 +7421,6 @@ int sqlite3Select( if( pTabList->a[j].fg.jointype & JT_RIGHT ) break; } } - assert( pItem->iCursor>=0 ); - unsetJoinExpr(p->pWhere, pItem->iCursor, - pTabList->a[0].fg.jointype & JT_LTORJ); } /* No further action if this term of the FROM clause is not a subquery */ diff --git a/test/joinH.test b/test/joinH.test index 0fed7f2aa0..9f61002cb7 100644 --- a/test/joinH.test +++ b/test/joinH.test @@ -250,5 +250,45 @@ do_catchsql_test 9.11 { SELECT oid FROM wo2 JOIN (wo3 JOIN x3) } {0 99} +reset_db +do_execsql_test 10.0 { + CREATE TABLE rt0 (c0 INTEGER, c1 INTEGER, c2 INTEGER, c3 INTEGER, c4 INTEGER); + CREATE TABLE rt3 (c3 INTEGER); + + INSERT INTO rt0(c3, c1) VALUES (x'', '1'); + INSERT INTO rt0(c3, c1) VALUES ('-1', -1e500); + INSERT INTO rt0(c3, c1) VALUES (1, x''); + + CREATE VIEW v6(c0, c1, c2) AS SELECT 0, 0, 0; +} + +do_execsql_test 10.1 { + SELECT COUNT(*) FROM rt0 LEFT JOIN rt3 JOIN v6 ON ((CASE v6.c0 WHEN rt0.c4 THEN rt3.c3 END) NOT BETWEEN (rt0.c4) AND (NULL)) WHERE (rt0.c1); -- 2 +} {0} + +do_execsql_test 10.2 { + SELECT COUNT(*) FROM rt0 LEFT JOIN rt3 RIGHT OUTER JOIN v6 ON ((CASE v6.c0 WHEN rt0.c4 THEN rt3.c3 END) NOT BETWEEN (rt0.c4) AND (NULL)) WHERE (rt0.c1); -- 2 +} {0} + +#------------------------------------------------------------------------- + +do_execsql_test 11.1 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(c, d); + CREATE TABLE t3(e, f); + + INSERT INTO t1 VALUES(1, 1); + INSERT INTO t2 VALUES(2, 2); + INSERT INTO t3 VALUES(3, 3); +} + +do_execsql_test 11.2 { + SELECT * FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON (t2.c=10) +} {{} {} {} {} 3 3} + +do_execsql_test 11.3 { + SELECT * FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON (t2.c=10) WHERE t1.a=1 +} {} + finish_test From 53381132be7ca901d821922f31bd62d4558fc489 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 10 Nov 2023 16:29:02 +0000 Subject: [PATCH 51/55] Remove a NEVER() from whereAddIndexedExpr() that is reachable if there is an unknown indexed function in the schema. FossilOrigin-Name: a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 853509f8ea..18ac9d03d9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sobscure\sproblem\swith\sthe\sjoin-strength-reduction\soptimization\sthat\scould\soccur\swhen\smixing\sLEFT\sand\sRIGHT\sjoins\sin\sthe\ssame\squery.\s[forum:/forumpost/7f74ce0bee|Forum\spost\s7f74ce0bee]. -D 2023-11-10T15:03:18.325 +C Remove\sa\sNEVER()\sfrom\swhereAddIndexedExpr()\sthat\sis\sreachable\sif\sthere\nis\san\sunknown\sindexed\sfunction\sin\sthe\sschema. +D 2023-11-10T16:29:02.318 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -809,7 +809,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c d6ac0f598e725412af5b4484fe98187a129f3c8778c7dbc18ac7477294e190ca +F src/where.c 5b14ccd10ed4cfa3d62fa83bfa623aeda4d26dbc9f451c895a21797f0a024436 F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 @@ -2139,8 +2139,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 ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739 -R a50d2c9cbe89dc0abaae6ac9eaaaf01b -U dan -Z c2b696ca5d071695417bed8717dba32c +P 530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536 +R cdb270c91f1e1a38ee4163db25142a2e +U drh +Z 1057cabad660e84de38d4c1b258b7805 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e7c169124b..109d74f0b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536 \ No newline at end of file +a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f \ No newline at end of file diff --git a/src/where.c b/src/where.c index 555bd6a349..48722a8a82 100644 --- a/src/where.c +++ b/src/where.c @@ -5820,7 +5820,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( assert( ExprUseXList(pExpr) ); n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ + if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ continue; } } From 5a81e6e5cedb29be1ce8d41053c27e5b4a4f82fd Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 10 Nov 2023 17:49:26 +0000 Subject: [PATCH 52/55] Ensure 8-byte alignment of data structues in sqlite3_database_file_object(). This should have appeared on trunk originally and then be cherry-picked onto the branch. Oh well.... FossilOrigin-Name: ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30 --- manifest | 13 +++++++------ manifest.uuid | 2 +- src/pager.c | 5 ++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 18ac9d03d9..fadd914708 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\sNEVER()\sfrom\swhereAddIndexedExpr()\sthat\sis\sreachable\sif\sthere\nis\san\sunknown\sindexed\sfunction\sin\sthe\sschema. -D 2023-11-10T16:29:02.318 +C Ensure\s8-byte\salignment\sof\sdata\sstructues\sin\ssqlite3_database_file_object().\nThis\sshould\shave\sappeared\son\strunk\soriginally\sand\sthen\sbe\scherry-picked\sonto\nthe\sbranch.\s\sOh\swell.... +D 2023-11-10T17:49:26.551 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -711,7 +711,7 @@ F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d87210 F src/os_unix.c 0a33005e6426702c7e76f3d451f296c088693a95b2be28ba9ef59c8d8529ce6b F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 699aab8dfc88056d796b03b40c0ab979040d58dfc3ae9db207f1be91e4880bbf +F src/pager.c 987ab3a2cd9065d62e9955474470ff733445e2357432a67e3d0f5a8f9313e334 F src/pager.h f4d33fec8052603758792045493423b8871a996da2d0973927b7d36cd6070473 F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75 @@ -2139,8 +2139,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536 -R cdb270c91f1e1a38ee4163db25142a2e +P a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f +Q +3cfcaafaff181c7945cc659ff6d58a0d2232d49830a259f0510d833a7a5a824b +R 1028456d182afa02f9e623f04c8760e0 U drh -Z 1057cabad660e84de38d4c1b258b7805 +Z a0dd8db0b2162f7029aa06a0eb66b266 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 109d74f0b0..fc184b9086 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f \ No newline at end of file +ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index e547504243..4687ab0f19 100644 --- a/src/pager.c +++ b/src/pager.c @@ -5062,10 +5062,13 @@ act_like_temp_file: */ sqlite3_file *sqlite3_database_file_object(const char *zName){ Pager *pPager; + const char *p; while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } - pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); + p = zName - 4 - sizeof(Pager*); + assert( EIGHT_BYTE_ALIGNMENT(p) ); + pPager = *(Pager**)p; return pPager->fd; } From 10c815a55d7c85dbb44972446c180a928a72dc73 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 10 Nov 2023 20:35:59 +0000 Subject: [PATCH 53/55] Remove an incorrect ALWAYS() that was inserted yesterday [1e039b6eb59c0001]. FossilOrigin-Name: 12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24 --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index fadd914708..38fe16f21c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\s8-byte\salignment\sof\sdata\sstructues\sin\ssqlite3_database_file_object().\nThis\sshould\shave\sappeared\son\strunk\soriginally\sand\sthen\sbe\scherry-picked\sonto\nthe\sbranch.\s\sOh\swell.... -D 2023-11-10T17:49:26.551 +C Remove\san\sincorrect\sALWAYS()\sthat\swas\sinserted\syesterday\s[1e039b6eb59c0001]. +D 2023-11-10T20:35:59.820 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -809,7 +809,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 5b14ccd10ed4cfa3d62fa83bfa623aeda4d26dbc9f451c895a21797f0a024436 +F src/where.c 45b2239e127beaaae2367e503ca4c82868d8fef707c7f7f4a6c0528e7d5f65ff F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00 @@ -2139,9 +2139,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 a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f -Q +3cfcaafaff181c7945cc659ff6d58a0d2232d49830a259f0510d833a7a5a824b -R 1028456d182afa02f9e623f04c8760e0 +P ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30 +R ab374843bab00dc7e7d0efa052218f4c U drh -Z a0dd8db0b2162f7029aa06a0eb66b266 +Z 6634464e9b33a08cf926f1b7b363008f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fc184b9086..a6c6e97165 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30 \ No newline at end of file +12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 48722a8a82..cfd5d5e1a5 100644 --- a/src/where.c +++ b/src/where.c @@ -5818,7 +5818,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr( FuncDef *pDef; sqlite3 *db = pParse->db; assert( ExprUseXList(pExpr) ); - n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0; + n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ continue; From 88dcfe56dab431ef7c1bad9b3f55cfcefc28e022 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 10 Nov 2023 20:46:58 +0000 Subject: [PATCH 54/55] Additional debugging information on the tree-dump of the BETWEEN operator. FossilOrigin-Name: aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/treeview.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 38fe16f21c..0f91f19c68 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sincorrect\sALWAYS()\sthat\swas\sinserted\syesterday\s[1e039b6eb59c0001]. -D 2023-11-10T20:35:59.820 +C Additional\sdebugging\sinformation\son\sthe\stree-dump\sof\sthe\sBETWEEN\soperator. +D 2023-11-10T20:46:58.376 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -787,7 +787,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5 -F src/treeview.c 62fafcd31eea60b718f8daf448116b7b19f90134ebc6c20777ddbb07f56a3d28 +F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81 F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92 F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242 @@ -2139,8 +2139,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 ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30 -R ab374843bab00dc7e7d0efa052218f4c +P 12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24 +R c3f7aa166734d4220835a7bad8ba4679 U drh -Z 6634464e9b33a08cf926f1b7b363008f +Z 09fad8e886637b8c34b5cfcae694bf8a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a6c6e97165..e81340ae83 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24 \ No newline at end of file +aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60 \ No newline at end of file diff --git a/src/treeview.c b/src/treeview.c index 1fad8673dd..2576532b65 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -781,7 +781,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ assert( pExpr->x.pList->nExpr==2 ); pY = pExpr->x.pList->a[0].pExpr; pZ = pExpr->x.pList->a[1].pExpr; - sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); sqlite3TreeViewExpr(pView, pZ, 0); From fb28a93f75af10d3cf305e1a8c1cb6656d781bdd Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 10 Nov 2023 20:55:20 +0000 Subject: [PATCH 55/55] Fix another problem with mixed join types and the RIGHT JOIN strength-reduction optimization. [forum:/forumpost/befdab472d | Forum post befdab472d]. FossilOrigin-Name: f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/select.c | 2 +- test/joinH.test | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 0f91f19c68..f1683dfa58 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\sdebugging\sinformation\son\sthe\stree-dump\sof\sthe\sBETWEEN\soperator. -D 2023-11-10T20:46:58.376 +C Fix\sanother\sproblem\swith\smixed\sjoin\stypes\sand\sthe\sRIGHT\sJOIN\sstrength-reduction\soptimization.\s[forum:/forumpost/befdab472d\s|\sForum\spost\sbefdab472d]. +D 2023-11-10T20:55:20.957 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -724,7 +724,7 @@ F src/printf.c 9da63b9ae1c14789bcae12840f5d800fd9302500cd2d62733fac77f0041b4750 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 47797c57c5ee2ad183b34a2e5d643ec7519366686bbe44a9a81df9fe304f28a7 +F src/select.c 503331aca8785254a7bf3d74ab338a99118fa297e1184a4dde33b3cdf7a9d341 F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140 F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1309,7 +1309,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2 F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28 F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127 -F test/joinH.test c4301c738b05b845f273b0d94de74e953626d809dc945352909aedb199b42e5f +F test/joinH.test f69e5b53b7d887914e854b6a131efbed4ea9f5ca52bdab81788bfc3e79299f43 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -2139,8 +2139,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 12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24 -R c3f7aa166734d4220835a7bad8ba4679 -U drh -Z 09fad8e886637b8c34b5cfcae694bf8a +P aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60 +R 97cf5703d60c0dd519713f02ba70db03 +U dan +Z e3c451988b970e006792a61910aa1f15 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e81340ae83..873b025efc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60 \ No newline at end of file +f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 \ No newline at end of file diff --git a/src/select.c b/src/select.c index c2685b370e..2b28d9ca5e 100644 --- a/src/select.c +++ b/src/select.c @@ -7416,7 +7416,7 @@ int sqlite3Select( } } } - for(j=pTabList->nSrc-1; j>=i; j--){ + for(j=pTabList->nSrc-1; j>=0; j--){ pTabList->a[j].fg.jointype &= ~JT_LTORJ; if( pTabList->a[j].fg.jointype & JT_RIGHT ) break; } diff --git a/test/joinH.test b/test/joinH.test index 9f61002cb7..3702266804 100644 --- a/test/joinH.test +++ b/test/joinH.test @@ -290,5 +290,23 @@ do_execsql_test 11.3 { SELECT * FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON (t2.c=10) WHERE t1.a=1 } {} +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 12.1 { + CREATE TABLE t1(a1 INT, b1 TEXT); + INSERT INTO t1 VALUES(88,''); + CREATE TABLE t2(c2 INT, d2 TEXT); + INSERT INTO t2 VALUES(88,''); + CREATE TABLE t3(e3 TEXT PRIMARY KEY); + INSERT INTO t3 VALUES(''); +} + +do_execsql_test 12.2 { + SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1; +} +do_execsql_test 12.3 { + SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1; +} finish_test