diff options
-rw-r--r-- | ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java | 153 | ||||
-rw-r--r-- | ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java | 24 | ||||
-rw-r--r-- | manifest | 17 | ||||
-rw-r--r-- | manifest.uuid | 2 |
4 files changed, 138 insertions, 58 deletions
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index bcf97b239..4cf06d355 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -77,7 +77,7 @@ public final class Sqlite implements AutoCloseable { */ sqlite3 nativeHandle(){ return this.db; } - private sqlite3 affirmOpen(){ + private sqlite3 thisDb(){ if( null==db || 0==db.getNativePointer() ){ throw new IllegalArgumentException("This database instance is closed."); } @@ -88,13 +88,59 @@ public final class Sqlite implements AutoCloseable { // return s==null ? null : s.getBytes(StandardCharsets.UTF_8); // } + /** + If rc!=0, throws an SqliteException. If this db is currently + opened, the error state is extracted from it, else only the + string form of rc is used. + */ private void affirmRcOk(int rc){ if( 0!=rc ){ - throw new SqliteException(db); + if( null==db ) throw new SqliteException(rc); + else throw new SqliteException(db); } } /** + prepare() TODOs include: + + - 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. + */ + 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); + affirmRcOk(rc); + return new Stmt(this, out.take()); + } + + public Stmt prepare(String sql){ + return prepare(sql, 0); + } + + 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)); + if( 0!=rc ) throw new SqliteException(db); + } + + public void createFunction(String name, int nArg, ScalarFunction f){ + this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); + } + + public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f ){ + int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep, + new SqlFunction.AggregateAdapter(f)); + if( 0!=rc ) throw new SqliteException(db); + } + + public void createFunction(String name, int nArg, AggregateFunction f){ + this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); + } + + /** Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to create new instances. */ @@ -111,7 +157,11 @@ public final class Sqlite implements AutoCloseable { return stmt; } - private sqlite3_stmt affirmOpen(){ + /** + If this statement is still opened, its low-level handle is + returned, eelse an IllegalArgumentException is thrown. + */ + private sqlite3_stmt thisStmt(){ if( null==stmt || 0==stmt.getNativePointer() ){ throw new IllegalArgumentException("This Stmt has been finalized."); } @@ -140,7 +190,9 @@ public final class Sqlite implements AutoCloseable { /** Throws if rc is any value other than 0, SQLITE_ROW, or - SQLITE_DONE, else returns rc. + SQLITE_DONE, else returns rc. Error state for the exception is + extracted from this statement object (if it's opened) or the + string form of rc. */ private int checkRc(int rc){ switch(rc){ @@ -148,7 +200,8 @@ public final class Sqlite implements AutoCloseable { case SQLITE_ROW: case SQLITE_DONE: return rc; default: - throw new SqliteException(this); + if( null==stmt ) throw new SqliteException(rc); + else throw new SqliteException(this); } } @@ -157,7 +210,7 @@ public final class Sqlite implements AutoCloseable { result other than 0, SQLITE_ROW, or SQLITE_DONE. */ public int step(){ - return checkRc(sqlite3_step(affirmOpen())); + return checkRc(sqlite3_step(thisStmt())); } public Sqlite db(){ return this._db; } @@ -166,53 +219,55 @@ public final class Sqlite implements AutoCloseable { Works like sqlite3_reset() but throws on error. */ public void reset(){ - checkRc(sqlite3_reset(affirmOpen())); + checkRc(CApi.sqlite3_reset(thisStmt())); } public void clearBindings(){ - sqlite3_clear_bindings( affirmOpen() ); + CApi.sqlite3_clear_bindings( thisStmt() ); + } + public void bindInt(int ndx, int val){ + checkRc(CApi.sqlite3_bind_int(thisStmt(), ndx, val)); + } + public void bindInt64(int ndx, long val){ + checkRc(CApi.sqlite3_bind_int64(thisStmt(), ndx, val)); + } + public void bindDouble(int ndx, double val){ + checkRc(CApi.sqlite3_bind_double(thisStmt(), ndx, val)); + } + public void bindObject(int ndx, Object o){ + checkRc(CApi.sqlite3_bind_java_object(thisStmt(), ndx, o)); + } + public void bindNull(int ndx){ + checkRc(CApi.sqlite3_bind_null(thisStmt(), ndx)); + } + public int bindParameterCount(){ + return CApi.sqlite3_bind_parameter_count(thisStmt()); + } + public int bindParameterIndex(String paramName){ + return CApi.sqlite3_bind_parameter_index(thisStmt(), paramName); + } + public String bindParameterName(int ndx){ + return CApi.sqlite3_bind_parameter_name(thisStmt(), ndx); + } + public void bindText(int ndx, byte[] utf8){ + checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, utf8)); + } + public void bindText(int ndx, String asUtf8){ + checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, asUtf8)); + } + 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 bindZeroBlob(int ndx, int n){ + checkRc(CApi.sqlite3_bind_zeroblob(thisStmt(), ndx, n)); + } + public void bindBlob(int ndx, byte[] bytes){ + checkRc(CApi.sqlite3_bind_blob(thisStmt(), ndx, bytes)); } - } - - - /** - prepare() TODOs include: - - - 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. - */ - public Stmt prepare(String sql, int prepFlags){ - final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt(); - final int rc = sqlite3_prepare_v3(affirmOpen(), sql, prepFlags, out); - affirmRcOk(rc); - return new Stmt(this, out.take()); - } - - public Stmt prepare(String sql){ - return prepare(sql, 0); - } - - public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f ){ - int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep, - new SqlFunction.ScalarAdapter(f)); - if( 0!=rc ) throw new SqliteException(db); - } - - public void createFunction(String name, int nArg, ScalarFunction f){ - this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); - } - - public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f ){ - int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep, - new SqlFunction.AggregateAdapter(f)); - if( 0!=rc ) throw new SqliteException(db); - } - public void createFunction(String name, int nArg, AggregateFunction f){ - this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); - } + } /* 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 f5fd5f84e..cf3364bc1 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -224,8 +224,26 @@ public class Tester2 implements Runnable { void testPrepare1(){ try (Sqlite db = openDb()) { - Sqlite.Stmt stmt = db.prepare("SELECT 1"); + Sqlite.Stmt stmt = db.prepare("SELECT ?1"); + Exception e = null; affirm( null!=stmt.nativeHandle() ); + 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); + stmt.bindNull(1); + stmt.bindText(1, new byte[] {32,32,32}); + stmt.bindText(1, "123"); + stmt.bindText16(1, "123".getBytes(StandardCharsets.UTF_16)); + stmt.bindText16(1, "123"); + stmt.bindZeroBlob(1, 8); + stmt.bindBlob(1, new byte[] {1,2,3,4}); + try{ stmt.bindInt(2,1); } + catch(Exception ex){ e = ex; } + affirm( null!=e ); affirm( CApi.SQLITE_ROW == stmt.step() ); affirm( CApi.SQLITE_DONE == stmt.step() ); stmt.reset(); @@ -269,6 +287,10 @@ 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); try (Sqlite db = openDb()) { @@ -1,5 +1,5 @@ -C JNI:\simprove\sUB\sprotections\sin\ssqlite3_bind_blob/text/text16(). -D 2023-10-22T12:33:05.772 +C Add\sJNI\swrapper1.SqliteStmt.bindXyz()\sAPIs. +D 2023-10-22T12:43:30.072 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 a9ddc6a9e8c113168cc67592ae24c0e56d30dd06226eeab012f2761a0889d7bb +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 25e4e65ba434d0e110e4adb6782e20cd374d83b7fe00ba5ca48a1dadd2fdd7dd F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java c24b510ebe801c30533cc62efdf69a4a5e2da9ec4b49f8d403f2060693f060a0 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 65437e09115bfef4445957db61fcf6dac9aad37ac00edb445c3de812e9750d6e 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,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 b8258103fb433d9f5cfa15661b5edf4e60128fb4161d8a18e5cc3253e5aed72b -R 10dd3eddc3858c0c90f96d7af2dd213f +P 5c8383210a87d7f9d37a27053b5b1b6f41794fa8612826c68c1ca49c495cbd97 +R 186cd14750afba6ac11c0a47787c2fc3 +T *branch * jni-post-3.44 +T *sym-jni-post-3.44 * +T -sym-trunk * Cancelled\sby\sbranch. U stephan -Z 39a3acd541e66480809465cadb3002fa +Z dc6c06549901a63430a6e90b2648f01f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bcfb4efa9..166d31ff9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c8383210a87d7f9d37a27053b5b1b6f41794fa8612826c68c1ca49c495cbd97
\ No newline at end of file +54fce9bf04a7517cdc8e96fe2efec66f03b0d03983c3a45d0ae7e1f16aa5a6c9
\ No newline at end of file |