1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

JNI: change sqlite3_prepare_multi()'s exception-handling semantics to be more C-like and, to support that, add the package-private sqlite3_jni_db_error() method to set the db error state from package-level Java code.

FossilOrigin-Name: 46656b354311ec0a36832af1c4ccb3b6a244aa55cfb3681e25c3f42b13b387dd
This commit is contained in:
stephan
2023-11-14 02:43:30 +00:00
parent b481413d95
commit adcd13d243
8 changed files with 98 additions and 31 deletions

View File

@@ -3879,7 +3879,9 @@ S3JniApi(sqlite3_is_interrupted(),jboolean,1is_1interrupted)(
** any resources owned by that cache entry and making that slot
** available for re-use.
*/
JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
S3JniApi(sqlite3_java_uncache_thread(), jboolean, 1java_1uncache_1thread)(
JniArgsEnvClass
){
int rc;
S3JniEnv_mutex_enter;
rc = S3JniEnv_uncache(env);
@@ -3887,7 +3889,25 @@ JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
return rc ? JNI_TRUE : JNI_FALSE;
}
JniDecl(jboolean,1jni_1supports_1nio)(JniArgsEnvClass){
S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
JniArgsEnvClass, jobject jDb, jint jRc, jstring jStr
){
S3JniDb * const ps = S3JniDb_from_java(jDb);
int rc = SQLITE_MISUSE;
if( ps ){
char *zStr;
zStr = jStr
? s3jni_jstring_to_utf8( jStr, 0)
: NULL;
rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
sqlite3_free(zStr);
}
return rc;
}
S3JniApi(sqlite3_jni_supports_nio(), jboolean,1jni_1supports_1nio)(
JniArgsEnvClass
){
return SJG.g.cByteBuffer ? JNI_TRUE : JNI_FALSE;
}
@@ -4065,10 +4085,11 @@ S3JniApi(sqlite3_open_v2(),jint,1open_1v2)(
}
/* Proxy for the sqlite3_prepare[_v2/3]() family. */
jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self,
jlong jpDb, jbyteArray baSql,
jint nMax, jint prepFlags,
jobject jOutStmt, jobject outTail){
static jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env,
jclass self,
jlong jpDb, jbyteArray baSql,
jint nMax, jint prepFlags,
jobject jOutStmt, jobject outTail){
sqlite3_stmt * pStmt = 0;
jobject jStmt = 0;
const char * zTail = 0;

View File

@@ -785,6 +785,14 @@ JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
(JNIEnv *, jclass);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_jni_db_error
* Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1db_1error
(JNIEnv *, jclass, jobject, jint, jstring);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_aggregate_context

View File

@@ -131,6 +131,25 @@ public final class CApi {
*/
public static native boolean sqlite3_jni_supports_nio();
/**
For internal use only. Sets the given db's error code and
(optionally) string. If rc is 0, it defaults to SQLITE_ERROR.
On success it returns rc. On error it may return a more serious
code, such as SQLITE_NOMEM. Returns SQLITE_MISUSE if db is null.
*/
static native int sqlite3_jni_db_error(@NotNull sqlite3 db,
int rc, @Nullable String msg);
/**
Convenience overload which uses e.toString() as the error
message.
*/
static int sqlite3_jni_db_error(@NotNull sqlite3 db,
int rc, @NotNull Exception e){
return sqlite3_jni_db_error(db, rc, e.toString());
}
//////////////////////////////////////////////////////////////////////
// Maintenance reminder: please keep the sqlite3_.... functions
// alphabetized. The SQLITE_... values. on the other hand, are
@@ -1324,9 +1343,13 @@ public final class CApi {
array. It loops over the input bytes looking for
statements. Each one it finds is passed to p.call(), passing
ownership of it to that function. If p.call() returns 0, looping
continues, else the loop stops.
continues, else the loop stops and p.call()'s result code is
returned. If preparation of any given segment fails, looping
stops and that result code is returned.
<p>If p.call() throws, the exception is propagated.
<p>If p.call() throws, the exception is converted to a db-level
error and a non-0 code is returned, in order to retain the
C-style error semantics of the API.
<p>How each statement is handled, including whether it is finalized
or not, is up to the callback object. e.g. the callback might
@@ -1358,7 +1381,11 @@ public final class CApi {
// empty statement (whitespace/comments)
continue;
}
rc = p.call(stmt);
try{
rc = p.call(stmt);
}catch(Exception e){
rc = sqlite3_jni_db_error( db, SQLITE_ERROR, e );
}
}
return rc;
}

View File

@@ -25,7 +25,10 @@ public interface PrepareMultiCallback extends CallbackProxy {
sqlite3_prepare_multi() will _not_ finalize st - it is up
to the call() implementation how st is handled.
Must return 0 on success or an SQLITE_... code on error.
Must return 0 on success or an SQLITE_... code on error. If it
throws, sqlite3_prepare_multi() will transform the exception into
a db-level error in order to retain the C-style error semantics
of the API.
See the {@link Finalize} class for a wrapper which finalizes the
statement after calling a proxy PrepareMultiCallback.
@@ -37,7 +40,7 @@ public interface PrepareMultiCallback extends CallbackProxy {
any sqlite3_stmt passed to its callback.
*/
public static final class Finalize implements PrepareMultiCallback {
private PrepareMultiCallback p;
private final PrepareMultiCallback p;
/**
p is the proxy to call() when this.call() is called.
*/

View File

@@ -1790,9 +1790,13 @@ public class Tester1 implements Runnable {
};
final List<sqlite3_stmt> liStmt = new ArrayList<sqlite3_stmt>();
final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
final ValueHolder<String> toss = new ValueHolder<>(null);
PrepareMultiCallback m = new PrepareMultiCallback() {
@Override public int call(sqlite3_stmt st){
liStmt.add(st);
if( null!=toss.value ){
throw new RuntimeException(toss.value);
}
return proxy.call(st);
}
};
@@ -1802,6 +1806,10 @@ public class Tester1 implements Runnable {
for( sqlite3_stmt st : liStmt ){
sqlite3_finalize(st);
}
toss.value = "This is an exception.";
rc = sqlite3_prepare_multi(db, "SELECT 1", m);
affirm( SQLITE_ERROR==rc );
affirm( sqlite3_errmsg(db).indexOf(toss.value)>0 );
sqlite3_close_v2(db);
}

View File

@@ -605,6 +605,14 @@ public final class Sqlite implements AutoCloseable {
prepareMulti( sql, 0, visitor );
}
/**
Equivallent to prepareMulti(X,prepFlags,visitor), where X is
sql.getBytes(StandardCharsets.UTF_8).
*/
public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
}
/**
A variant of prepare() which can handle multiple SQL statements
in a single input string. For each statement in the given string,
@@ -646,14 +654,6 @@ public final class Sqlite implements AutoCloseable {
}
}
/**
Equivallent to prepareMulti(X,prepFlags,visitor), where X is
sql.getBytes(StandardCharsets.UTF_8).
*/
public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
}
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));

View File

@@ -1,5 +1,5 @@
C JNI:\sadd\ssqlite3_blob_write()\soverload\swhich\saccepts\sa\sjava.nio.ByteBuffer.\sCleanups\sin\sadjacent\scode.
D 2023-11-14T01:33:15.332
C JNI:\schange\ssqlite3_prepare_multi()'s\sexception-handling\ssemantics\sto\sbe\smore\sC-like\sand,\sto\ssupport\sthat,\sadd\sthe\spackage-private\ssqlite3_jni_db_error()\smethod\sto\sset\sthe\sdb\serror\sstate\sfrom\spackage-level\sJava\scode.
D 2023-11-14T02:43:30.475
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -241,8 +241,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9cd020d4
F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c 0668675c6ec44a4109035d7236233867cd3bfc63f82bbb5a1c679ab412f795ba
F ext/jni/src/c/sqlite3-jni.h a7c4b87b200d6eb2745867c7d955941c56bc035ddee79b2c7382822565aa17c2
F ext/jni/src/c/sqlite3-jni.c 7d14bf998e9862ecf01b121067b745eeb75668ca0a431df6e2a86fb5a500bca5
F ext/jni/src/c/sqlite3-jni.h b8876cce091767e0655200b7653dc5a0ae117b53cff7b1090e9dbc2e69775ed5
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba
F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
@@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
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 d8424b0fb29b6c2bd0753eca5a026c007e967a093421094207b32bb147123699
F ext/jni/src/org/sqlite/jni/capi/CApi.java e96ed33a5c235082a59bf73d861acbbb7b760f2c790ac719e495d8512e4de8c3
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
@@ -260,7 +260,7 @@ F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93a
F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33
F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61
F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 246b0e66c4603f41c567105a21189d138aaf8c58203ecd4928802333da553e7c
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java aca8f9fa72e3b6602bc9a7dd3ae9f5b2808103fbbee9b2749dc96c19cdc261a1
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java 97352091abd7556167f4799076396279a51749fdae2b72a6ba61cd39b3df0359
F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java efcf57545c5e282d1dd332fa63329b3b218d98f356ef107a9dbe3979be82213a
F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b
F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f
@@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385
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 738fa19c2688fe22eb856edf2292e846d6804748f00d6b753ecdea627095c5f8
F ext/jni/src/org/sqlite/jni/capi/Tester1.java fb0d859a07988bf0757b0910431d8d12a5f7f177eb7e7632f27eebc524b2aa92
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950
@@ -296,7 +296,7 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java aeaec95323a8186d0b8e741affff067fe893849a2d862acd443373035c7b73a0
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 671bf57fe1801e06c5026194e987669ec456434c3224cf138878c7f4a69e8f09
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
@@ -2139,8 +2139,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 efbc82b218d26b7ca9b881da69d5fd14d22b5211fbd85a835da50e5bfde3d160
R b363dc4648f62c28510d70ed94844bbc
P ca32af8542aa2725cc87f54541b19897556f610e4674edf9f22a84e3d4097a82
R 8cb29fe765a47cc780c8d97ffc39bea6
U stephan
Z 47e30de17d53e7dab348193d2caa8c99
Z 32cdbaea235e75a5f5809e209395feaf
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
ca32af8542aa2725cc87f54541b19897556f610e4674edf9f22a84e3d4097a82
46656b354311ec0a36832af1c4ccb3b6a244aa55cfb3681e25c3f42b13b387dd