From: stephan Date: Sun, 22 Oct 2023 14:25:37 +0000 (+0000) Subject: JNI: flesh out and simplify the APIs for binding and fetching arbitrary Java objects. X-Git-Tag: version-3.45.0~232^2~7 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=166c8d00671fbd16057cc3dc6523af336591a1c5;p=thirdparty%2Fsqlite.git JNI: flesh out and simplify the APIs for binding and fetching arbitrary Java objects. FossilOrigin-Name: 89fecf1dd8b97941f9b45130a3c8a67af36ec65cc6f70f5026c569c058a4963f --- diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 245ce4f9e9..86a4930917 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -1670,8 +1670,9 @@ static int encodingTypeIsValid(int eTextRep){ } } -/* For use with sqlite3_result/value_pointer() */ -static const char * const ResultJavaValuePtrStr = "org.sqlite.jni.capi.ResultJavaVal"; +/* For use with sqlite3_result_pointer(), sqlite3_value_pointer(), + sqlite3_bind_java_object(), and sqlite3_column_java_object(). */ +static const char * const s3jni__value_jref_key = "org.sqlite.jni.capi.ResultJavaVal"; /* ** If v is not NULL, it must be a jobject global reference. Its @@ -2418,7 +2419,7 @@ S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)( if(pStmt){ jobject const rv = S3JniRefGlobal(val); if( rv ){ - rc = sqlite3_bind_pointer(pStmt, ndx, rv, ResultJavaValuePtrStr, + rc = sqlite3_bind_pointer(pStmt, ndx, rv, s3jni__value_jref_key, S3Jni_jobject_finalizer); }else if(val){ rc = SQLITE_NOMEM; @@ -2870,6 +2871,26 @@ S3JniApi(sqlite3_column_int64(),jlong,1column_1int64)( return (jlong)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx); } +S3JniApi(sqlite3_column_java_object(),jobject,1column_1java_1object)( + JniArgsEnvClass, jlong jpStmt, jint ndx +){ + sqlite3_stmt * const stmt = S3JniLongPtr_sqlite3_stmt(jpStmt); + jobject rv = 0; + if( stmt ){ + sqlite3 * const db = sqlite3_db_handle(stmt); + sqlite3_value * sv; + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + sv = sqlite3_column_value(stmt, (int)ndx); + if( sv ){ + rv = S3JniRefLocal( + sqlite3_value_pointer(sv, s3jni__value_jref_key) + ); + } + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + } + return rv; +} + S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)( JniArgsEnvClass, jobject jpStmt, jint ndx ){ @@ -4351,7 +4372,7 @@ S3JniApi(sqlite3_result_java_object(),void,1result_1java_1object)( jobject const rjv = S3JniRefGlobal(v); if( rjv ){ sqlite3_result_pointer(pCx, rjv, - ResultJavaValuePtrStr, S3Jni_jobject_finalizer); + s3jni__value_jref_key, S3Jni_jobject_finalizer); }else{ sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx)); } @@ -4889,7 +4910,7 @@ S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)( ){ sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal); return sv - ? sqlite3_value_pointer(sv, ResultJavaValuePtrStr) + ? sqlite3_value_pointer(sv, s3jni__value_jref_key) : 0; } diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index bf6df7ac94..6c4d07fc43 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1119,6 +1119,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int64 (JNIEnv *, jclass, jobject, jint); +/* + * Class: org_sqlite_jni_capi_CApi + * Method: sqlite3_column_java_object + * Signature: (JI)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1java_1object + (JNIEnv *, jclass, jlong, jint); + /* * Class: org_sqlite_jni_capi_CApi * Method: sqlite3_column_name diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 302cdb760e..ff5da01c65 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -595,6 +595,36 @@ public final class CApi { @NotNull sqlite3_stmt stmt, int ndx ); + static native Object sqlite3_column_java_object( + @NotNull long ptrToStmt, int ndx + ); + + /** + If the given result column was bound with + sqlite3_bind_java_object() or sqlite3_result_java_object() then + that object is returned, else null is returned. This routine + requires locking the owning database's mutex briefly in order to + extract the object in a thread-safe way. + */ + public static Object sqlite3_column_java_object( + @NotNull sqlite3_stmt stmt, int ndx + ){ + return sqlite3_column_java_object( stmt.getNativePointer(), ndx ); + } + + /** + If the two-parameter overload of sqlite3_column_java_object() + returns non-null and the returned value is an instance of T then + that object is returned, else null is returned. + */ + @SuppressWarnings("unchecked") + public static T sqlite3_column_java_object( + @NotNull sqlite3_stmt stmt, int ndx, @NotNull Class type + ){ + final Object o = sqlite3_column_java_object(stmt, ndx); + return type.isInstance(o) ? (T)o : null; + } + static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx); public static String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx){ @@ -1938,7 +1968,7 @@ public final class CApi { given Class, else it returns null. */ @SuppressWarnings("unchecked") - public static T sqlite3_value_java_casted(@NotNull sqlite3_value v, + public static T sqlite3_value_java_object(@NotNull sqlite3_value v, @NotNull Class type){ final Object o = sqlite3_value_java_object(v); return type.isInstance(o) ? (T)o : null; diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 6fb28e65b9..b1d8df11cd 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -803,13 +803,17 @@ public class Tester1 implements Runnable { affirm( 0==rc ); int n = 0; if( SQLITE_ROW == sqlite3_step(stmt) ){ + affirm( testResult.value == sqlite3_column_java_object(stmt, 0) ); + affirm( testResult.value == sqlite3_column_java_object(stmt, 0, sqlite3.class) ); + affirm( null == sqlite3_column_java_object(stmt, 0, sqlite3_stmt.class) ); + affirm( null == sqlite3_column_java_object(stmt,1) ); final sqlite3_value v = sqlite3_column_value(stmt, 0); affirm( testResult.value == sqlite3_value_java_object(v) ); - affirm( testResult.value == sqlite3_value_java_casted(v, sqlite3.class) ); + affirm( testResult.value == sqlite3_value_java_object(v, sqlite3.class) ); affirm( testResult.value == - sqlite3_value_java_casted(v, testResult.value.getClass()) ); - affirm( testResult.value == sqlite3_value_java_casted(v, Object.class) ); - affirm( null == sqlite3_value_java_casted(v, String.class) ); + sqlite3_value_java_object(v, testResult.value.getClass()) ); + affirm( testResult.value == sqlite3_value_java_object(v, Object.class) ); + affirm( null == sqlite3_value_java_object(v, String.class) ); ++n; } sqlite3_finalize(stmt); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index d6acda5aa5..2e0be3cd63 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -72,7 +72,7 @@ public interface SqlFunction { public int getBytes(){return a.getBytes(ndx);} public int getBytes16(){return a.getBytes16(ndx);} public Object getObject(){return a.getObject(ndx);} - public T getObjectCasted(Class type){ return a.getObjectCasted(ndx, type); } + public T getObject(Class type){ return a.getObject(ndx, type); } public int getType(){return a.getType(ndx);} public Object getAuxData(){return a.getAuxData(ndx);} public void setAuxData(Object o){a.setAuxData(ndx, o);} @@ -113,8 +113,8 @@ public interface SqlFunction { public int getBytes(int arg){return CApi.sqlite3_value_bytes(valueAt(arg));} public int getBytes16(int arg){return CApi.sqlite3_value_bytes16(valueAt(arg));} public Object getObject(int arg){return CApi.sqlite3_value_java_object(valueAt(arg));} - public T getObjectCasted(int arg, Class type){ - return CApi.sqlite3_value_java_casted(valueAt(arg), type); + public T getObject(int arg, Class type){ + return CApi.sqlite3_value_java_object(valueAt(arg), type); } public int getType(int arg){return CApi.sqlite3_value_type(valueAt(arg));} diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index cefc0aa78b..25628e0805 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -329,6 +329,12 @@ public final class Sqlite implements AutoCloseable { public int columnDataCount(){ return CApi.sqlite3_data_count( thisStmt() ); } + public Object columnObject(int ndx){ + return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx ); + } + public T columnObject(int ndx, Class type){ + return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx, type ); + } public String columnName(int ndx){ return CApi.sqlite3_column_name( checkColIndex(ndx), ndx ); } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 6756478f58..8fb36a3b54 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -261,9 +261,13 @@ public class Tester2 implements Runnable { affirm( 0 == stmt.finalizeStmt() ); affirm( null==stmt.nativeHandle() ); - stmt = db.prepare("SELECT 1"); + stmt = db.prepare("SELECT ?"); + stmt.bindObject(1, db); affirm( CApi.SQLITE_ROW == stmt.step() ); - affirm( 0 == stmt.finalizeStmt() ) + affirm( db==stmt.columnObject(0) ); + affirm( db==stmt.columnObject(0, Sqlite.class ) ); + affirm( null==stmt.columnObject(0, Sqlite.Stmt.class ) ); + affirm( 0==stmt.finalizeStmt() ) /* getting a non-0 out of sqlite3_finalize() is tricky */; affirm( null==stmt.nativeHandle() ); } diff --git a/manifest b/manifest index 66f9eea687..d20131a353 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C JNI:\sflesh\sout\sand\ssimplify\sthe\sAPIs\sfor\sbinding\sand\sfetching\sarbitrary\sJava\sobjects. +D 2023-10-22T14:25:37.634 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -239,8 +239,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile 5c3ac326bf3853486ebe0d70819abc790cc65c412182ce4ebd5012b008d9b059 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 6f6df9657989e9ca2cfdcc2fe9a71c279de56d5c941adfd09a0f24256de35c8f -F ext/jni/src/c/sqlite3-jni.h b4c413a0d0c734683da1049cfcf89e35ae2719759d0656ec0f8c57188f18cab8 +F ext/jni/src/c/sqlite3-jni.c dcd6534b65b732ad927a49185c76c76abbd5ccadfa972d02f699abc45678e329 +F ext/jni/src/c/sqlite3-jni.h e839090f5ec35aa96983a5621659e55ef897dc0522242fd00f107028ef5e7dd5 F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2 F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca @@ -249,7 +249,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java bc29e986c866c2ddbbb9f93 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 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 bccb442ca81cd4decb1adae99006a60b7a9f54e5153842e738c01104e97d1de0 +F ext/jni/src/org/sqlite/jni/capi/CApi.java f23e8139cdb1d9c850f28ccf95384e37239cee47fd683bfb199f50aa7ce011fc F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 0bfd6e56e8265c2f05c9207665707285534d78f8466ef0e0430c65677f00943d F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95 @@ -267,7 +267,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java fef556adbc3624292423083a648bd F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java ca195521b6bda3e0cd00e76bb71ec8060d1fab76a2f13b1af9feea40789f44bb +F ext/jni/src/org/sqlite/jni/capi/Tester1.java 5c4e7ba5034aeb5c5be0361b9fa0c23fe993774e634750c775d7ad8fa19b22f3 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 @@ -293,10 +293,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 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 b0ee72b60b2a15d3f19571213f62e560134d6517eacece73eb1299b6d9980f14 +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 92c28b9de358407c8c5e772e0408db528e47eeeb50ffd87b86563a5f078198ad +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 882e345d925a79b575b1182efd816dcc72d6814922b4f58e7f4d29f04ece1f64 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 5ff33f3e31f5d88178e485ab334e8fb6ccf8ad1f6666136b4a613fec58888432 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java e224efb77dae2f0abe18f2010c0eb5a09df991f2743597a1aff7f9283f71da7d 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 f3fb4d345bbf5ae4a35d8076043df601b1bf7dfd68760a416440139eb3e5eb9a -R 4d4dd7480ffdece828c7f766b6d86d96 +P 60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287 +R 5a1e4de3384c2859d02b694c480544f0 U stephan -Z e88e3b32c9f23fead743fdff8331a212 +Z 0b6f35d12f929147f1a8dbbd84db96f1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 32e6dcdc5e..a425b28981 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287 \ No newline at end of file +89fecf1dd8b97941f9b45130a3c8a67af36ec65cc6f70f5026c569c058a4963f \ No newline at end of file