Add JNI wrapper1.SqliteStmt.bindXyz() APIs.

FossilOrigin-Name: 54fce9bf04a7517cdc8e96fe2efec66f03b0d03983c3a45d0ae7e1f16aa5a6c9
This commit is contained in:
stephan
2023-10-22 12:43:30 +00:00
parent 28f45b1ab1
commit 4bcde614d8
4 changed files with 138 additions and 58 deletions
+104 -49
View File
@@ -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,12 +88,58 @@ 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 */
}
@@ -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()) {
+10 -7
View File
@@ -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.
+1 -1
View File
@@ -1 +1 @@
5c8383210a87d7f9d37a27053b5b1b6f41794fa8612826c68c1ca49c495cbd97
54fce9bf04a7517cdc8e96fe2efec66f03b0d03983c3a45d0ae7e1f16aa5a6c9