]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Wrap more of the stmt API behind the JNI wrapper1 API.
authorstephan <stephan@noemail.net>
Fri, 3 Nov 2023 13:00:51 +0000 (13:00 +0000)
committerstephan <stephan@noemail.net>
Fri, 3 Nov 2023 13:00:51 +0000 (13:00 +0000)
FossilOrigin-Name: 8fea23dc3af023ccf2909f1b4c6f91e7df0ffaac875b15f1fb3e264fba169b6a

ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java
ext/jni/src/org/sqlite/jni/capi/ValueHolder.java
ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
manifest
manifest.uuid

index 0495702561ef83f37ccffb1d09ed15ee86c012cf..7df748e8d8381868f45ca14481c6c0a135b8ebd8 100644 (file)
@@ -24,8 +24,9 @@ package org.sqlite.jni.capi;
    propagated.  For callback interfaces which support returning error
    info to the core, the JNI binding will convert any exceptions to
    C-level error information. For callback interfaces which do not
-   support, all exceptions will necessarily be suppressed in order to
-   retain the C-style no-throw semantics.
+   support returning error information, all exceptions will
+   necessarily be suppressed in order to retain the C-style no-throw
+   semantics and avoid invoking undefined behavior in the C layer.
 
    <p>Callbacks of this style follow a common naming convention:
 
index b3f03ac867e1cf8d8a255a0cf09f8710141af320..6d5db3f669ce4f1b34078e1b953f9d7365427c2d 100644 (file)
@@ -9,14 +9,15 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** This file contains a set of tests for the sqlite3 JNI bindings.
+** This file holds utility code for the sqlite3 JNI bindings.
 */
 package org.sqlite.jni.capi;
 
 /**
    A helper class which simply holds a single value. Its primary use
    is for communicating values out of anonymous classes, as doing so
-   requires a "final" reference.
+   requires a "final" reference, as well as communicating aggregate
+   SQL function state across calls to such functions.
 */
 public class ValueHolder<T> {
   public T value;
index 2d0ebfaf32b342a159fb449add73fbee83f3c418..5bcb3bd5faec9a0876bd62de0d5a63a1bb9ceba1 100644 (file)
@@ -121,6 +121,17 @@ public interface SqlFunction  {
     public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
     public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}
 
+    /**
+       Callbacks should invoke this on OOM errors, instead of throwing
+       OutOfMemoryError, because the latter cannot be propagated
+       through the C API.
+    */
+    public void resultNoMem(){CApi.sqlite3_result_error_nomem(cx);}
+
+    /**
+       Analog to sqlite3_set_auxdata() but throws if argNdx is out of
+       range.
+    */
     public void setAuxData(int argNdx, Object o){
       /* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html
 
@@ -132,6 +143,10 @@ public interface SqlFunction  {
       CApi.sqlite3_set_auxdata(cx, argNdx, o);
     }
 
+    /**
+       Analog to sqlite3_get_auxdata() but throws if argNdx is out of
+       range.
+    */
     public Object getAuxData(int argNdx){
       valueAt(argNdx);
       return CApi.sqlite3_get_auxdata(cx, argNdx);
index 6bb87cc3921778102108bdf7c4bc6a34803144b9..907755d99a9de8c9799718e4402490e8509dd1a2 100644 (file)
@@ -210,11 +210,19 @@ public final class Sqlite implements AutoCloseable  {
      extracted from it, else only the string form of rc is used. It is
      the caller's responsibility to filter out non-error codes such as
      SQLITE_ROW and SQLITE_DONE before calling this.
+
+     As a special case, if rc is SQLITE_NOMEM, an OutOfMemoryError is
+     thrown.
   */
   private void checkRc(int rc){
     if( 0!=rc ){
-      if( null==db || 0==sqlite3_errcode(db)) throw new SqliteException(rc);
-      else throw new SqliteException(db);
+      if( CApi.SQLITE_NOMEM==rc ){
+        throw new OutOfMemoryError();
+      }else if( null==db || 0==sqlite3_errcode(db)){
+        throw new SqliteException(rc);
+      }else{
+        throw new SqliteException(db);
+      }
     }
   }
 
@@ -470,8 +478,11 @@ public final class Sqlite implements AutoCloseable  {
        We save the result column count in order to prevent having to
        call into C to fetch that value every time we need to check
        that value for the columnXyz() methods.
+
+       Design note: if this is final then we cannot zero it in
+       finalizeStmt().
     */
-    private final int resultColCount;
+    private int resultColCount;
 
     /** Only called by the prepare() factory functions. */
     Stmt(Sqlite db, sqlite3_stmt stmt){
@@ -509,13 +520,17 @@ public final class Sqlite implements AutoCloseable  {
        name finalize() here because this one requires a different
        signature. It does not throw on error here because "destructors
        do not throw." If it returns non-0, the object is still
-       finalized.
+       finalized, but the result code is an indication that something
+       went wrong in a prior call into the statement's API, as
+       documented for sqlite3_finalize().
     */
     public int finalizeStmt(){
       int rc = 0;
       if( null!=stmt ){
         sqlite3_finalize(stmt);
         stmt = null;
+        _db = null;
+        resultColCount = 0;
       }
       return rc;
     }
@@ -565,6 +580,10 @@ 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; }
 
     /**
@@ -574,6 +593,44 @@ public final class Sqlite implements AutoCloseable  {
       checkRc(CApi.sqlite3_reset(thisStmt()));
     }
 
+    public boolean isBusy(){
+      return CApi.sqlite3_stmt_busy(thisStmt());
+    }
+
+    public boolean isReadOnly(){
+      return CApi.sqlite3_stmt_readonly(thisStmt());
+    }
+
+    public String sql(){
+      return CApi.sqlite3_sql(thisStmt());
+    }
+
+    public String expandedSql(){
+      return CApi.sqlite3_expanded_sql(thisStmt());
+    }
+
+    /**
+       Analog to sqlite3_stmt_explain() but throws if op is invalid.
+    */
+    public void explain(int op){
+      checkRc(CApi.sqlite3_stmt_explain(thisStmt(), op));
+    }
+
+    /**
+       Analog to sqlite3_stmt_isexplain().
+    */
+    public int isExplain(){
+      return CApi.sqlite3_stmt_isexplain(thisStmt());
+    }
+
+    /**
+       Analog to sqlite3_normalized_sql(), returning null if the
+       library is built without the SQLITE_ENABLE_NORMALIZE flag.
+    */
+    public String normalizedSql(){
+      return CApi.sqlite3_normalized_sql(thisStmt());
+    }
+
     public void clearBindings(){
       CApi.sqlite3_clear_bindings( thisStmt() );
     }
@@ -610,8 +667,8 @@ public final class Sqlite implements AutoCloseable  {
     public void bindText16(int ndx, byte[] utf16){
       checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, utf16));
     }
-    public void bindText16(int ndx, String txt){
-      checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, txt));
+    public void bindText16(int ndx, String asUtf16){
+      checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, asUtf16));
     }
     public void bindZeroBlob(int ndx, int n){
       checkRc(CApi.sqlite3_bind_zeroblob(thisStmt(), ndx, n));
index e6de9ab0184ed91636f1046e9cb2079cd1da9f25..d24551ebf1eabb00d288d735563018167d1356c4 100644 (file)
@@ -422,6 +422,28 @@ public class Tester2 implements Runnable {
     affirm( null==Sqlite.keywordName(n) );
   }
 
+
+  private void testExplain(){
+    final Sqlite db = openDb();
+    Sqlite.Stmt q = db.prepare("SELECT 1");
+    affirm( 0 == q.isExplain() );
+    q.explain(0);
+    affirm( 0 == q.isExplain() );
+    q.explain(1);
+    affirm( 1 == q.isExplain() );
+    q.explain(2);
+    affirm( 2 == q.isExplain() );
+    Exception ex = null;
+    try{
+      q.explain(-1);
+    }catch(Exception e){
+      ex = e;
+    }
+    affirm( ex instanceof SqliteException );
+    q.finalizeStmt();
+    db.close();
+  }
+
   private void runTests(boolean fromThread) throws Exception {
     List<java.lang.reflect.Method> mlist = testMethods;
     affirm( null!=mlist );
index a27a5977bc403acc26b842a793cfd9b29ca13459..0a014ab96c64ae17f2c0a74eb6c40b4c094e45e4 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Bind\sthe\ssqlite3_keyword_...()\sand\ssqlite3_compileoption_...()\sfamily\sof\sfunctions\sto\sthe\sJNI\swrapper1\sAPI.
-D 2023-11-03T11:53:13.823
+C Wrap\smore\sof\sthe\sstmt\sAPI\sbehind\sthe\sJNI\swrapper1\sAPI.
+D 2023-11-03T13:00:51.184
 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/AuthorizerCallback.java 7ed409d5449684616cc924
 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/CallbackProxy.java 0bfd6e56e8265c2f05c9207665707285534d78f8466ef0e0430c65677f00943d
+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/CommitHookCallback.java 29c002f3c638cc80f7db1594564a262d1beb32637824c3dca2d60a224d1f71d7
@@ -271,7 +271,7 @@ F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff22
 F ext/jni/src/org/sqlite/jni/capi/Tester1.java b6b2f3354ba68956a6bcd1c586b8eb25a0bd66eed2b58b340405e1129da15de9
 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 9f9e151f1da017b706c0ee5f40f4c86b54e773d6ae4339723e0cc85a456251ab
+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
 F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e
@@ -294,10 +294,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 bbe60ac7fd8718edb215a23dc901771bcedb1df3b46d9cf6caff6f419828587f
 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
-F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 9be20f3ba6edbe63285224d5d640dbfb0d84fb8cf5134084e3ae40004ec9d6d9
-F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 698fd699dd113fa2bceb78d3565f3d4578dee86150fb86e1838ec915994aa57b
+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/SqliteException.java aa85b4b05fae240b14f3d332f9524a2f80c619fb03856be72b4adda866b63b72
-F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java f74b9000cc24d415cfdd9fd77234aa6ab0549871f495529993cee6176cad0329
+F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 9ab7e38e6741842f8e3b74cd3ecb4953e2f1957f5229bd32663df7331245ce95
 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
@@ -2141,8 +2141,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 52ab3deba4d26ca0e9a84a6dff254195b4a0e2cc6cf948cf7a66bb11117e7002
-R 713111c1d3b2b5aa68a4fe22b929906b
+P b27242414d6023eac7e62cf6120e1f02b0ddc7b8f0a1e4c48111cfe88d197cbd
+R 05c1b264db19fc6b766555a4fdb5a28d
 U stephan
-Z 5f0fb960919ed3f05e59594d37935544
+Z 7009b77b29804732443dad34d2696167
 # Remove this line to create a well-formed Fossil manifest.
index 0a15fa2c89f6ab69475c61ec17553cba18dd2c4d..88247987ba938b72ae2081ec5da43233ac73fbc5 100644 (file)
@@ -1 +1 @@
-b27242414d6023eac7e62cf6120e1f02b0ddc7b8f0a1e4c48111cfe88d197cbd
\ No newline at end of file
+8fea23dc3af023ccf2909f1b4c6f91e7df0ffaac875b15f1fb3e264fba169b6a
\ No newline at end of file