mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Reimplement auto-extensions in Java for use with the JNI wrapper1 API.
FossilOrigin-Name: 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468
This commit is contained in:
@ -891,7 +891,7 @@ public final class CApi {
|
||||
}
|
||||
|
||||
public static native boolean sqlite3_extended_result_codes(
|
||||
@NotNull sqlite3 db, boolean onoff
|
||||
@NotNull sqlite3 db, boolean on
|
||||
);
|
||||
|
||||
static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb);
|
||||
|
@ -1419,7 +1419,7 @@ public class Tester1 implements Runnable {
|
||||
|
||||
val.value = 0;
|
||||
final AutoExtensionCallback ax2 = new AutoExtensionCallback(){
|
||||
@Override public synchronized int call(sqlite3 db){
|
||||
@Override public int call(sqlite3 db){
|
||||
++val.value;
|
||||
return 0;
|
||||
}
|
||||
|
@ -117,6 +117,10 @@ public interface SqlFunction {
|
||||
public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
|
||||
public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
|
||||
public void resultNull(){CApi.sqlite3_result_null(cx);}
|
||||
/**
|
||||
Analog to sqlite3_result_value(), using the Value object at the
|
||||
given argument index.
|
||||
*/
|
||||
public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
|
||||
public void resultSubtype(int subtype){CApi.sqlite3_result_subtype(cx, subtype);}
|
||||
public void resultZeroBlob(long n){
|
||||
|
@ -13,7 +13,6 @@
|
||||
*/
|
||||
package org.sqlite.jni.wrapper1;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import static org.sqlite.jni.capi.CApi.*;
|
||||
import org.sqlite.jni.capi.CApi;
|
||||
import org.sqlite.jni.capi.sqlite3;
|
||||
import org.sqlite.jni.capi.sqlite3_stmt;
|
||||
@ -129,7 +128,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
*/
|
||||
public static Sqlite open(String filename, int flags, String vfsName){
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
final int rc = sqlite3_open_v2(filename, out, flags, vfsName);
|
||||
final int rc = CApi.sqlite3_open_v2(filename, out, flags, vfsName);
|
||||
final sqlite3 n = out.take();
|
||||
if( 0!=rc ){
|
||||
if( null==n ) throw new SqliteException(rc);
|
||||
@ -137,10 +136,11 @@ public final class Sqlite implements AutoCloseable {
|
||||
n.close();
|
||||
throw ex;
|
||||
}
|
||||
Sqlite rv = new Sqlite(n);
|
||||
final Sqlite rv = new Sqlite(n);
|
||||
synchronized(nativeToWrapper){
|
||||
nativeToWrapper.put(n, rv);
|
||||
}
|
||||
runAutoExtensions(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
}
|
||||
|
||||
public static Sqlite open(String filename){
|
||||
return open(filename, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, null);
|
||||
return open(filename, OPEN_READWRITE|OPEN_CREATE, null);
|
||||
}
|
||||
|
||||
public static String libVersion(){
|
||||
@ -308,7 +308,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
if( 0!=rc ){
|
||||
if( CApi.SQLITE_NOMEM==rc ){
|
||||
throw new OutOfMemoryError();
|
||||
}else if( null==db || 0==sqlite3_errcode(db)){
|
||||
}else if( null==db || 0==CApi.sqlite3_errcode(db)){
|
||||
throw new SqliteException(rc);
|
||||
}else{
|
||||
throw new SqliteException(db);
|
||||
@ -343,7 +343,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
*/
|
||||
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);
|
||||
final int rc = CApi.sqlite3_prepare_v3(thisDb(), sql, prepFlags, out);
|
||||
checkRc(rc);
|
||||
final sqlite3_stmt q = out.take();
|
||||
if( null==q ){
|
||||
@ -724,7 +724,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
synchronized(nativeToWrapper){
|
||||
nativeToWrapper.remove(this.stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
CApi.sqlite3_finalize(stmt);
|
||||
stmt = null;
|
||||
_db = null;
|
||||
resultColCount = 0;
|
||||
@ -745,8 +745,8 @@ public final class Sqlite implements AutoCloseable {
|
||||
private int checkRc(int rc){
|
||||
switch(rc){
|
||||
case 0:
|
||||
case SQLITE_ROW:
|
||||
case SQLITE_DONE: return rc;
|
||||
case CApi.SQLITE_ROW:
|
||||
case CApi.SQLITE_DONE: return rc;
|
||||
default:
|
||||
if( null==stmt ) throw new SqliteException(rc);
|
||||
else throw new SqliteException(this);
|
||||
@ -759,7 +759,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
result.
|
||||
*/
|
||||
public boolean step(){
|
||||
switch(checkRc(sqlite3_step(thisStmt()))){
|
||||
switch(checkRc(CApi.sqlite3_step(thisStmt()))){
|
||||
case CApi.SQLITE_ROW: return true;
|
||||
case CApi.SQLITE_DONE: return false;
|
||||
default:
|
||||
@ -930,4 +930,93 @@ public final class Sqlite implements AutoCloseable {
|
||||
}
|
||||
} /* Stmt class */
|
||||
|
||||
/**
|
||||
Interface for auto-extensions, as per the
|
||||
sqlite3_auto_extension() API.
|
||||
|
||||
Design note: the chicken/egg timing of auto-extension execution
|
||||
requires that this feature be entirely re-implemented in Java
|
||||
because the C-level API has no access to the Sqlite type so
|
||||
cannot pass on an object of that type while the database is being
|
||||
opened. One side effect of this reimplementation is that this
|
||||
class's list of auto-extensions is 100% independent of the
|
||||
C-level list so, e.g., clearAutoExtensions() will have no effect
|
||||
on auto-extensions added via the C-level API and databases opened
|
||||
from that level of API will not be passed to this level's
|
||||
AutoExtension instances.
|
||||
*/
|
||||
public interface AutoExtension {
|
||||
public void call(Sqlite db);
|
||||
}
|
||||
|
||||
private static final java.util.Set<AutoExtension> autoExtensions =
|
||||
new java.util.LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
Passes db to all auto-extensions. If any one of them throws,
|
||||
db.close() is called before the exception is propagated.
|
||||
*/
|
||||
private static void runAutoExtensions(Sqlite db){
|
||||
AutoExtension list[];
|
||||
synchronized(autoExtensions){
|
||||
/* Avoid that modifications to the AutoExtension list from within
|
||||
auto-extensions affect this execution of this list. */
|
||||
list = autoExtensions.toArray(new AutoExtension[0]);
|
||||
}
|
||||
try {
|
||||
for( AutoExtension ax : list ) ax.call(db);
|
||||
}catch(Exception e){
|
||||
db.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Analog to sqlite3_auto_extension(), adds the given object to the
|
||||
list of auto-extensions if it is not already in that list. The
|
||||
given object will be run as part of Sqlite.open(), and passed the
|
||||
being-opened database. If the extension throws then open() will
|
||||
fail.
|
||||
|
||||
This API does not guaranty whether or not manipulations made to
|
||||
the auto-extension list from within auto-extension callbacks will
|
||||
affect the current traversal of the auto-extension list. Whether
|
||||
or not they do is unspecified and subject to change between
|
||||
versions. e.g. if an AutoExtension calls addAutoExtension(),
|
||||
whether or not the new extension will be run on the being-opened
|
||||
database is undefined.
|
||||
|
||||
Note that calling Sqlite.open() from an auto-extension will
|
||||
necessarily result in recursion loop and (eventually) a stack
|
||||
overflow.
|
||||
*/
|
||||
public static void addAutoExtension( AutoExtension e ){
|
||||
if( null==e ){
|
||||
throw new IllegalArgumentException("AutoExtension may not be null.");
|
||||
}
|
||||
synchronized(autoExtensions){
|
||||
autoExtensions.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Removes the given object from the auto-extension list if it is in
|
||||
that list, otherwise this has no side-effects beyond briefly
|
||||
locking that list.
|
||||
*/
|
||||
public static void removeAutoExtension( AutoExtension e ){
|
||||
synchronized(autoExtensions){
|
||||
autoExtensions.remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all auto-extensions which were added via addAutoExtension().
|
||||
*/
|
||||
public static void clearAutoExtensions(){
|
||||
synchronized(autoExtensions){
|
||||
autoExtensions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -526,6 +526,83 @@ public class Tester2 implements Runnable {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@SingleThreadOnly /* because multiple threads legitimately make these
|
||||
results unpredictable */
|
||||
private synchronized void testAutoExtension(){
|
||||
final ValueHolder<Integer> val = new ValueHolder<>(0);
|
||||
final ValueHolder<String> toss = new ValueHolder<>(null);
|
||||
final Sqlite.AutoExtension ax = new Sqlite.AutoExtension(){
|
||||
@Override public void call(Sqlite db){
|
||||
++val.value;
|
||||
if( null!=toss.value ){
|
||||
throw new RuntimeException(toss.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
Sqlite.addAutoExtension(ax);
|
||||
openDb().close();
|
||||
affirm( 1==val.value );
|
||||
openDb().close();
|
||||
affirm( 2==val.value );
|
||||
Sqlite.clearAutoExtensions();
|
||||
openDb().close();
|
||||
affirm( 2==val.value );
|
||||
|
||||
Sqlite.addAutoExtension( ax );
|
||||
Sqlite.addAutoExtension( ax ); // Must not add a second entry
|
||||
Sqlite.addAutoExtension( ax ); // or a third one
|
||||
openDb().close();
|
||||
affirm( 3==val.value );
|
||||
|
||||
Sqlite db = openDb();
|
||||
affirm( 4==val.value );
|
||||
execSql(db, "ATTACH ':memory:' as foo");
|
||||
affirm( 4==val.value, "ATTACH uses the same connection, not sub-connections." );
|
||||
db.close();
|
||||
db = null;
|
||||
|
||||
Sqlite.removeAutoExtension(ax);
|
||||
openDb().close();
|
||||
affirm( 4==val.value );
|
||||
Sqlite.addAutoExtension(ax);
|
||||
Exception err = null;
|
||||
toss.value = "Throwing from auto_extension.";
|
||||
try{
|
||||
openDb();
|
||||
}catch(Exception e){
|
||||
err = e;
|
||||
}
|
||||
affirm( err!=null );
|
||||
affirm( err.getMessage().indexOf(toss.value)>=0 );
|
||||
toss.value = null;
|
||||
|
||||
val.value = 0;
|
||||
final Sqlite.AutoExtension ax2 = new Sqlite.AutoExtension(){
|
||||
@Override public void call(Sqlite db){
|
||||
++val.value;
|
||||
}
|
||||
};
|
||||
Sqlite.addAutoExtension(ax2);
|
||||
openDb().close();
|
||||
affirm( 2 == val.value );
|
||||
Sqlite.removeAutoExtension(ax);
|
||||
openDb().close();
|
||||
affirm( 3 == val.value );
|
||||
Sqlite.addAutoExtension(ax);
|
||||
openDb().close();
|
||||
affirm( 5 == val.value );
|
||||
Sqlite.removeAutoExtension(ax2);
|
||||
openDb().close();
|
||||
affirm( 6 == val.value );
|
||||
Sqlite.addAutoExtension(ax2);
|
||||
openDb().close();
|
||||
affirm( 8 == val.value );
|
||||
|
||||
Sqlite.clearAutoExtensions();
|
||||
openDb().close();
|
||||
affirm( 8 == val.value );
|
||||
}
|
||||
|
||||
private void runTests(boolean fromThread) throws Exception {
|
||||
List<java.lang.reflect.Method> mlist = testMethods;
|
||||
affirm( null!=mlist );
|
||||
|
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
||||
C Ensure\sthat\sthe\sYYYY-MM-DD\sinput\sto\sdate\sand\stime\sfunctions\shas\sbeen\snormalized\nprior\sto\sreturning\sa\sresult.\n[forum:/forumpost/6bb476897e|Forum\spost\s6bb476897e].
|
||||
D 2023-11-04T21:44:00.659
|
||||
C Reimplement\sauto-extensions\sin\sJava\sfor\suse\swith\sthe\sJNI\swrapper1\sAPI.
|
||||
D 2023-11-04T21:51:34.589
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
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 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 d21e6c1c4557ae18bbc2eefb0882efdb36fdaecdc58823c142def994327a365b
|
||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java 4043d709626079cce6d524ef49122b934c043022bd88bc1e72eb697ac8df86e7
|
||||
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 f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95
|
||||
@ -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 41e2b910a11dfdd4cc39ab608492d7c12f3791e85ac7f9d75d5445f7645a5e57
|
||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java 96c27ae10ec44ce5f6a150e8bc6525d86ab2d9118da18649943a0bf4d8d206ce
|
||||
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 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950
|
||||
@ -295,10 +295,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 d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java e787f5f36d5832fe3c7a000a8609eb0629fb160b95f8f25566df13e72e6f5470
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3e813aa4a680948a1885a5df1537c9245b3b7362aaf6aa31f679640e81da020e
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3da22cb18d8544fff1c7184aeaa2516c20d63e8a31db848eb7470ce285b284dc
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 96d7908da8bad591aff8f192cb83e038fd5861ef4601726eeda24905422718c9
|
||||
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 03638a1774a95bcc7b5de440a5f1398720460e30fc480032a2e8be24e997d30c
|
||||
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/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.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566
|
||||
R 0a52dbd298d991529b412673e9dc7eb5
|
||||
U drh
|
||||
Z 33b6056e932d878d8676b163d8b94db2
|
||||
P b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5
|
||||
R 99817a8518af3f567a07823f0172a1fb
|
||||
U stephan
|
||||
Z 276f4a4bca9307a54b6144f3c8e4f323
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5
|
||||
14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468
|
Reference in New Issue
Block a user