From: stephan Date: Sun, 22 Oct 2023 13:54:26 +0000 (+0000) Subject: JNI: add column-get bindings to the wrapper1 Stmt class and extend the AggregateFunct... X-Git-Tag: version-3.45.0~232^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32a0d6129f240829f2d8811800869f7998b4b5e8;p=thirdparty%2Fsqlite.git JNI: add column-get bindings to the wrapper1 Stmt class and extend the AggregateFunction tests to ensure that the aggregate context is honored. FossilOrigin-Name: 60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287 --- diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 4cf06d355c..cefc0aa78b 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -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 */ } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index cf3364bc16..6756478f58 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -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 xDestroyCalled = new ValueHolder<>(0); - final ValueHolder 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(){ @@ -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 { diff --git a/manifest b/manifest index d4e1eb3da2..66f9eea687 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index 237845ed02..32e6dcdc5e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f3fb4d345bbf5ae4a35d8076043df601b1bf7dfd68760a416440139eb3e5eb9a \ No newline at end of file +60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287 \ No newline at end of file