]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
JNI: add column-get bindings to the wrapper1 Stmt class and extend the AggregateFunct...
authorstephan <stephan@noemail.net>
Sun, 22 Oct 2023 13:54:26 +0000 (13:54 +0000)
committerstephan <stephan@noemail.net>
Sun, 22 Oct 2023 13:54:26 +0000 (13:54 +0000)
FossilOrigin-Name: 60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287

ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
manifest
manifest.uuid

index 4cf06d355c7953b081ba1e85c6b349597c83a8c8..cefc0aa78bc2f28d936ebdc2236fe2756ca61c88 100644 (file)
@@ -147,10 +147,18 @@ public final class Sqlite implements AutoCloseable  {
   public final class Stmt implements AutoCloseable {
     private Sqlite _db = null;
     private sqlite3_stmt stmt = null;
+    /**
+       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.
+    */
+    private final int resultColCount;
+
     /** Only called by the prepare() factory functions. */
     Stmt(Sqlite db, sqlite3_stmt stmt){
       this._db = db;
       this.stmt = stmt;
+      this.resultColCount = CApi.sqlite3_column_count(stmt);
     }
 
     sqlite3_stmt nativeHandle(){
@@ -168,6 +176,15 @@ public final class Sqlite implements AutoCloseable  {
       return stmt;
     }
 
+    /** Throws if n is out of range of this.resultColCount. Intended
+        to be used by the columnXyz() methods. */
+    private sqlite3_stmt checkColIndex(int n){
+      if(n<0 || n>=this.resultColCount){
+        throw new IllegalArgumentException("Column index "+n+" is out of range.");
+      }
+      return thisStmt();
+    }
+
     /**
        Corresponds to sqlite3_finalize(), but we cannot override the
        name finalize() here because this one requires a different
@@ -211,6 +228,14 @@ public final class Sqlite implements AutoCloseable  {
     */
     public int step(){
       return checkRc(sqlite3_step(thisStmt()));
+      /*
+        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.
+      */
     }
 
     public Sqlite db(){ return this._db; }
@@ -268,6 +293,54 @@ public final class Sqlite implements AutoCloseable  {
       checkRc(CApi.sqlite3_bind_blob(thisStmt(), ndx, bytes));
     }
 
+    public byte[] columnBlob(int ndx){
+      return CApi.sqlite3_column_blob( checkColIndex(ndx), ndx );
+    }
+    public byte[] columnText(int ndx){
+      return CApi.sqlite3_column_text( checkColIndex(ndx), ndx );
+    }
+    public String columnText16(int ndx){
+      return CApi.sqlite3_column_text16( checkColIndex(ndx), ndx );
+    }
+    public int columnBytes(int ndx){
+      return CApi.sqlite3_column_bytes( checkColIndex(ndx), ndx );
+    }
+    public int columnBytes16(int ndx){
+      return CApi.sqlite3_column_bytes16( checkColIndex(ndx), ndx );
+    }
+    public int columnInt(int ndx){
+      return CApi.sqlite3_column_int( checkColIndex(ndx), ndx );
+    }
+    public long columnInt64(int ndx){
+      return CApi.sqlite3_column_int64( checkColIndex(ndx), ndx );
+    }
+    public double columnDouble(int ndx){
+      return CApi.sqlite3_column_double( checkColIndex(ndx), ndx );
+    }
+    public int columnType(int ndx){
+      return CApi.sqlite3_column_type( checkColIndex(ndx), ndx );
+    }
+    public String columnDeclType(int ndx){
+      return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx );
+    }
+    public int columnCount(){
+      return resultColCount;
+    }
+    public int columnDataCount(){
+      return CApi.sqlite3_data_count( thisStmt() );
+    }
+    public String columnName(int ndx){
+      return CApi.sqlite3_column_name( checkColIndex(ndx), ndx );
+    }
+    public String columnDatabaseName(int ndx){
+      return CApi.sqlite3_column_database_name( checkColIndex(ndx), ndx );
+    }
+    public String columnOriginName(int ndx){
+      return CApi.sqlite3_column_origin_name( checkColIndex(ndx), ndx );
+    }
+    public String columnTableName(int ndx){
+      return CApi.sqlite3_column_table_name( checkColIndex(ndx), ndx );
+    }
   } /* Stmt class */
 
 }
index cf3364bc16156469d53ea1944881e88b2d96c8ed..6756478f585e97db959b3caa296c1a1bba2ba05b 100644 (file)
@@ -230,7 +230,6 @@ public class Tester2 implements Runnable {
       affirm( 1==stmt.bindParameterCount() );
       affirm( "?1".equals(stmt.bindParameterName(1)) );
       affirm( null==stmt.bindParameterName(2) );
-      stmt.bindInt(1, 1);
       stmt.bindInt64(1, 1);
       stmt.bindDouble(1, 1.1);
       stmt.bindObject(1, db);
@@ -241,10 +240,20 @@ public class Tester2 implements Runnable {
       stmt.bindText16(1, "123");
       stmt.bindZeroBlob(1, 8);
       stmt.bindBlob(1, new byte[] {1,2,3,4});
+      stmt.bindInt(1, 17);
       try{ stmt.bindInt(2,1); }
       catch(Exception ex){ e = ex; }
       affirm( null!=e );
+      e = null;
       affirm( CApi.SQLITE_ROW == stmt.step() );
+      try{ stmt.columnInt(1); }
+      catch(Exception ex){ e = ex; }
+      affirm( null!=e );
+      e = null;
+      affirm( 17 == stmt.columnInt(0) );
+      affirm( 17L == stmt.columnInt64(0) );
+      affirm( 17.0 == stmt.columnDouble(0) );
+      affirm( "17".equals(stmt.columnText16(0)) );
       affirm( CApi.SQLITE_DONE == stmt.step() );
       stmt.reset();
       affirm( CApi.SQLITE_ROW == stmt.step() );
@@ -287,12 +296,8 @@ public class Tester2 implements Runnable {
   }
 
   void testUdfAggregate(){
-    /* FIXME/TODO: once we've added the stmt bind/step/fetch
-       capabilities, go back and extend these tests to correspond to
-       the aggregate UDF tests in ext/wasm/tester1.c-pp.js. We first
-       require the ability to bind/step/fetch, however. */
     final ValueHolder<Integer> xDestroyCalled = new ValueHolder<>(0);
-    final ValueHolder<Integer> vh = new ValueHolder<>(0);
+    Sqlite.Stmt q = null;
     try (Sqlite db = openDb()) {
       execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
       final AggregateFunction f = new AggregateFunction<Integer>(){
@@ -306,18 +311,39 @@ public class Tester2 implements Runnable {
             final Integer v = this.takeAggregateState(args);
             if( null==v ) args.resultNull();
             else args.resultInt(v);
-            vh.value = v;
           }
           public void xDestroy(){
             ++xDestroyCalled.value;
           }
         };
-      db.createFunction("myagg", -1, f);
-      execSql(db, "select myagg(a) from t");
-      affirm( 6 == vh.value );
+      db.createFunction("summer", 1, f);
+      q = db.prepare(
+        "with cte(v) as ("+
+        "select 3 union all select 5 union all select 7"+
+        ") select summer(v), summer(v+1) from cte"
+        /* ------------------^^^^^^^^^^^ ensures that we're handling
+           sqlite3_aggregate_context() properly. */
+      );
+      affirm( CApi.SQLITE_ROW==q.step() );
+      affirm( 15==q.columnInt(0) );
+      q.finalizeStmt();
+      q = null;
       affirm( 0 == xDestroyCalled.value );
+      db.createFunction("summerN", -1, f);
+
+      q = db.prepare("select summerN(1,8,9), summerN(2,3,4)");
+      affirm( CApi.SQLITE_ROW==q.step() );
+      affirm( 18==q.columnInt(0) );
+      affirm( 9==q.columnInt(1) );
+      q.finalizeStmt();
+      q = null;
+
+    }/*db*/
+    finally{
+      if( null!=q ) q.finalizeStmt();
     }
-    affirm( 1 == xDestroyCalled.value );
+    affirm( 2 == xDestroyCalled.value
+            /* because we've bound the same instance twice */ );
   }
 
   private void runTests(boolean fromThread) throws Exception {
index d4e1eb3da2c1cb85d19f627b52d3c18b7d63d64c..66f9eea6873694013e73e64711617252ae66975e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sAPI_ARMOR\sto\ssqlite3_clear_bindings().
-D 2023-10-22T13:09:37.276
+C JNI:\sadd\scolumn-get\sbindings\sto\sthe\swrapper1\sStmt\sclass\sand\sextend\sthe\sAggregateFunction\stests\sto\sensure\sthat\sthe\saggregate\scontext\sis\shonored.
+D 2023-10-22T13:54:26.716
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -294,9 +294,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe
 F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java 5ad99bd74c85f56bbef324d9ec29b4048f4620547c9a80093d8586c3557f9f9a
 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 004394eeb944baa56e36cd7ae69ba6d4a52b52db3c49439db16e98270b861421
-F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 25e4e65ba434d0e110e4adb6782e20cd374d83b7fe00ba5ca48a1dadd2fdd7dd
+F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b0ee72b60b2a15d3f19571213f62e560134d6517eacece73eb1299b6d9980f14
 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73
-F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 65437e09115bfef4445957db61fcf6dac9aad37ac00edb445c3de812e9750d6e
+F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 5ff33f3e31f5d88178e485ab334e8fb6ccf8ad1f6666136b4a613fec58888432
 F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
 F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
 F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
@@ -2136,8 +2136,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 54fce9bf04a7517cdc8e96fe2efec66f03b0d03983c3a45d0ae7e1f16aa5a6c9
-R 17c045c95304ed4e3d6135c84273c496
+P f3fb4d345bbf5ae4a35d8076043df601b1bf7dfd68760a416440139eb3e5eb9a
+R 4d4dd7480ffdece828c7f766b6d86d96
 U stephan
-Z 1cc1c3ab8b0755073c3409e264c96da6
+Z e88e3b32c9f23fead743fdff8331a212
 # Remove this line to create a well-formed Fossil manifest.
index 237845ed02ecc2cb384b58e0f3dcf3c642762c8f..32e6dcdc5e8cd7214d466905a6c81dec7a2a9231 100644 (file)
@@ -1 +1 @@
-f3fb4d345bbf5ae4a35d8076043df601b1bf7dfd68760a416440139eb3e5eb9a
\ No newline at end of file
+60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287
\ No newline at end of file