mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-26 09:41:10 +03:00
Add Sqlite.prepareMulti() to JNI wrapper1, for preparing multiple statements from a single input.
FossilOrigin-Name: e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a
This commit is contained in:
@ -1202,26 +1202,26 @@ public final class CApi {
|
|||||||
*/
|
*/
|
||||||
public static int sqlite3_prepare_multi(
|
public static int sqlite3_prepare_multi(
|
||||||
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
|
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
|
||||||
int preFlags,
|
int prepFlags,
|
||||||
@NotNull PrepareMultiCallback p){
|
@NotNull PrepareMultiCallback p){
|
||||||
final OutputPointer.Int32 oTail = new OutputPointer.Int32();
|
final OutputPointer.Int32 oTail = new OutputPointer.Int32();
|
||||||
int pos = 0, n = 1;
|
int pos = 0, n = 1;
|
||||||
byte[] sqlChunk = sqlUtf8;
|
byte[] sqlChunk = sqlUtf8;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
|
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
|
||||||
while(0==rc && pos<sqlChunk.length){
|
while( 0==rc && pos<sqlChunk.length ){
|
||||||
sqlite3_stmt stmt = null;
|
sqlite3_stmt stmt = null;
|
||||||
if(pos > 0){
|
if( pos>0 ){
|
||||||
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
|
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
|
||||||
sqlChunk.length);
|
sqlChunk.length);
|
||||||
}
|
}
|
||||||
if( 0==sqlChunk.length ) break;
|
if( 0==sqlChunk.length ) break;
|
||||||
rc = sqlite3_prepare_v3(db, sqlChunk, preFlags, outStmt, oTail);
|
rc = sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail);
|
||||||
if( 0!=rc ) break;
|
if( 0!=rc ) break;
|
||||||
pos = oTail.value;
|
pos = oTail.value;
|
||||||
stmt = outStmt.take();
|
stmt = outStmt.take();
|
||||||
if( null == stmt ){
|
if( null==stmt ){
|
||||||
// empty statement was parsed.
|
// empty statement (whitespace/comments)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rc = p.call(stmt);
|
rc = p.call(stmt);
|
||||||
|
@ -510,19 +510,27 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Analog to sqlite3_prepare_v3(), this prepares the first SQL
|
||||||
|
statement from the given input string and returns it as a
|
||||||
|
Stmt. It throws an SqliteException if preparation fails or an
|
||||||
|
IllegalArgumentException if the input is empty (e.g. contains
|
||||||
|
only comments or whitespace).
|
||||||
|
|
||||||
|
The first argument must be SQL input in UTF-8 encoding.
|
||||||
|
|
||||||
prepFlags must be 0 or a bitmask of the PREPARE_... constants.
|
prepFlags must be 0 or a bitmask of the PREPARE_... constants.
|
||||||
|
|
||||||
prepare() TODOs include:
|
For processing multiple statements from a single input, use
|
||||||
|
prepareMulti().
|
||||||
|
|
||||||
- overloads taking byte[] and ByteBuffer.
|
Design note: though the C-level API succeeds with a null
|
||||||
|
statement object for empty inputs, that approach is cumbersome to
|
||||||
- multi-statement processing, like CApi.sqlite3_prepare_multi()
|
use in higher-level APIs because every prepared statement has to
|
||||||
but using a callback specific to the higher-level Stmt class
|
be checked for null before using it.
|
||||||
rather than the sqlite3_stmt class.
|
|
||||||
*/
|
*/
|
||||||
public Stmt prepare(String sql, int prepFlags){
|
public Stmt prepare(byte utf8Sql[], int prepFlags){
|
||||||
final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
|
final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
|
||||||
final int rc = CApi.sqlite3_prepare_v3(thisDb(), sql, prepFlags, out);
|
final int rc = CApi.sqlite3_prepare_v3(thisDb(), utf8Sql, prepFlags, out);
|
||||||
checkRc(rc);
|
checkRc(rc);
|
||||||
final sqlite3_stmt q = out.take();
|
final sqlite3_stmt q = out.take();
|
||||||
if( null==q ){
|
if( null==q ){
|
||||||
@ -539,10 +547,113 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
return new Stmt(this, q);
|
return new Stmt(this, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equivalent to prepare(X, prepFlags), where X is
|
||||||
|
sql.getBytes(StandardCharsets.UTF_8).
|
||||||
|
*/
|
||||||
|
public Stmt prepare(String sql, int prepFlags){
|
||||||
|
return prepare( sql.getBytes(StandardCharsets.UTF_8), prepFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equivalent to prepare(sql, 0).
|
||||||
|
*/
|
||||||
public Stmt prepare(String sql){
|
public Stmt prepare(String sql){
|
||||||
return prepare(sql, 0);
|
return prepare(sql, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Callback type for use with prepareMulti().
|
||||||
|
*/
|
||||||
|
public interface PrepareMulti {
|
||||||
|
/**
|
||||||
|
Gets passed a Stmt which it may handle in arbitrary ways.
|
||||||
|
Ownership of st is passed to this function. It must throw on
|
||||||
|
error.
|
||||||
|
*/
|
||||||
|
void call(Sqlite.Stmt st);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
A PrepareMulti implementation which calls another PrepareMulti
|
||||||
|
object and then finalizes its statement.
|
||||||
|
*/
|
||||||
|
public static class PrepareMultiFinalize implements PrepareMulti {
|
||||||
|
private final PrepareMulti pm;
|
||||||
|
/**
|
||||||
|
Proxies the given PrepareMulti via this object's call() method.
|
||||||
|
*/
|
||||||
|
public PrepareMultiFinalize(PrepareMulti proxy){
|
||||||
|
this.pm = proxy;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Passes st to the call() method of the object this one proxies,
|
||||||
|
then finalizes st, propagating any exceptions from call() after
|
||||||
|
finalizing st.
|
||||||
|
*/
|
||||||
|
@Override public void call(Stmt st){
|
||||||
|
try{ pm.call(st); }
|
||||||
|
finally{ st.finalizeStmt(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equivalent to prepareMulti(sql,0,visitor).
|
||||||
|
*/
|
||||||
|
public void prepareMulti(String sql, PrepareMulti visitor){
|
||||||
|
prepareMulti( sql, 0, visitor );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
A variant of prepare() which can handle multiple SQL statements
|
||||||
|
in a single input string. For each statement in the given string,
|
||||||
|
the statement is passed to visitor.call() a single time, passing
|
||||||
|
ownership of the statement to that function. This function does
|
||||||
|
not step() or close() statements - those operations are left to
|
||||||
|
caller or the visitor function.
|
||||||
|
|
||||||
|
Unlike prepare(), this function does not fail if the input
|
||||||
|
contains only whitespace or SQL comments. In that case it is up
|
||||||
|
to the caller to arrange for that to be an error (if desired).
|
||||||
|
|
||||||
|
PrepareMultiFinalize offers a proxy which finalizes each
|
||||||
|
statement after it is passed to another client-defined visitor.
|
||||||
|
*/
|
||||||
|
public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){
|
||||||
|
int pos = 0, n = 1;
|
||||||
|
byte[] sqlChunk = sqlUtf8;
|
||||||
|
final org.sqlite.jni.capi.OutputPointer.sqlite3_stmt outStmt =
|
||||||
|
new org.sqlite.jni.capi.OutputPointer.sqlite3_stmt();
|
||||||
|
final org.sqlite.jni.capi.OutputPointer.Int32 oTail =
|
||||||
|
new org.sqlite.jni.capi.OutputPointer.Int32();
|
||||||
|
while( pos < sqlChunk.length ){
|
||||||
|
sqlite3_stmt stmt = null;
|
||||||
|
if( pos>0 ){
|
||||||
|
sqlChunk = java.util.Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length);
|
||||||
|
}
|
||||||
|
if( 0==sqlChunk.length ) break;
|
||||||
|
checkRc(
|
||||||
|
CApi.sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail)
|
||||||
|
);
|
||||||
|
pos = oTail.value;
|
||||||
|
stmt = outStmt.take();
|
||||||
|
if( null==stmt ){
|
||||||
|
/* empty statement, e.g. only comments or whitespace, was parsed. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visitor.call(new Stmt(this, stmt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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){
|
public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){
|
||||||
int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
|
int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
|
||||||
new SqlFunction.ScalarAdapter(f));
|
new SqlFunction.ScalarAdapter(f));
|
||||||
|
@ -125,7 +125,7 @@ public class Tester2 implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void execSql(Sqlite db, String[] sql){
|
public static void execSql(Sqlite db, String sql[]){
|
||||||
execSql(db, String.join("", sql));
|
execSql(db, String.join("", sql));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,6 +938,37 @@ public class Tester2 implements Runnable {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testPrepareMulti(){
|
||||||
|
final ValueHolder<Integer> fCount = new ValueHolder<>(0);
|
||||||
|
final ValueHolder<Integer> mCount = new ValueHolder<>(0);
|
||||||
|
try (Sqlite db = openDb()) {
|
||||||
|
execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
|
||||||
|
db.createFunction("counter", -1, new ScalarFunction(){
|
||||||
|
@Override public void xFunc(SqlFunction.Arguments args){
|
||||||
|
++fCount.value;
|
||||||
|
args.resultNull();
|
||||||
|
}
|
||||||
|
public void xDestroy(){}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
final Sqlite.PrepareMulti pm = new Sqlite.PrepareMultiFinalize(
|
||||||
|
new Sqlite.PrepareMulti() {
|
||||||
|
@Override public void call(Sqlite.Stmt q){
|
||||||
|
++mCount.value;
|
||||||
|
while(q.step()){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
final String sql = "select counter(*) from t;"+
|
||||||
|
"select counter(*) from t; /* comment */"+
|
||||||
|
"select counter(*) from t; -- comment\n"
|
||||||
|
;
|
||||||
|
db.prepareMulti(sql, pm);
|
||||||
|
}
|
||||||
|
affirm( 3 == mCount.value );
|
||||||
|
affirm( 9 == fCount.value );
|
||||||
|
}
|
||||||
|
|
||||||
private void runTests(boolean fromThread) throws Exception {
|
private void runTests(boolean fromThread) throws Exception {
|
||||||
List<java.lang.reflect.Method> mlist = testMethods;
|
List<java.lang.reflect.Method> mlist = testMethods;
|
||||||
affirm( null!=mlist );
|
affirm( null!=mlist );
|
||||||
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Diverse\sminor\scleanups\sin\sthe\sJNI\spieces.
|
C Add\sSqlite.prepareMulti()\sto\sJNI\swrapper1,\sfor\spreparing\smultiple\sstatements\sfrom\sa\ssingle\sinput.
|
||||||
D 2023-11-07T13:44:29.266
|
D 2023-11-07T15:56:39.576
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -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/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
|
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/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java 27e3c73685e1068e51331cd083152e0a6357b02278cb67b7c103240dbc262a5d
|
F ext/jni/src/org/sqlite/jni/capi/CApi.java 170cfd6501f6a4e68073808f3046970a6dd73d2faf478cbc9bd23f159ff3a646
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
|
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/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
||||||
@ -296,9 +296,9 @@ 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/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
|
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7
|
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 6a310fe422d0daf79f7841c9b341f64d843ca7e85ef31829530623a81ecd25fa
|
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
|
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java a944fd0a9047a51a5074bffd707452d80cf06e715ebc78b541480ee98629fb93
|
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 2ecf37746f2d475a133b530ddaf9ba8a6a65ce238db0805cb8e410ee760d4793
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
|
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
|
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
|
||||||
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
|
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
|
||||||
@ -2142,8 +2142,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901
|
P 35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4
|
||||||
R 2e556ea528a12ae342b294a8936cf3da
|
R e808fc8487495cabb8d32f4b1af8109a
|
||||||
U stephan
|
U stephan
|
||||||
Z 63d82a638a6f714cab2831b5cda37824
|
Z 28ef3e488a5683b53a25a3e0e53067e7
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4
|
e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a
|
Reference in New Issue
Block a user