mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
JNI: add CONFIG_LOG and CONFIG_SQLLOG support to wrapper1. Code-adjacent cleanups.
FossilOrigin-Name: 83c49b9e71e5ae8852bab60a6fa630e22164c8efbf074c85450136781d0fffd3
This commit is contained in:
@ -93,7 +93,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
|
||||
CollationNeededCallback.java \
|
||||
CommitHookCallback.java \
|
||||
ConfigLogCallback.java \
|
||||
ConfigSqllogCallback.java \
|
||||
ConfigSqlLogCallback.java \
|
||||
NativePointerHolder.java \
|
||||
OutputPointer.java \
|
||||
PrepareMultiCallback.java \
|
||||
@ -322,7 +322,7 @@ test-one: $(test.deps)
|
||||
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
|
||||
test-sqllog: $(test.deps)
|
||||
@echo "Testing with -sqllog..."
|
||||
$(bin.java) $(test.flags.jvm) -sqllog
|
||||
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
|
||||
test-mt: $(test.deps)
|
||||
@echo "Testing in multi-threaded mode:";
|
||||
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
|
||||
|
@ -1300,7 +1300,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1CONFIG_1
|
||||
/*
|
||||
* Class: org_sqlite_jni_capi_CApi
|
||||
* Method: sqlite3_config__SQLLOG
|
||||
* Signature: (Lorg/sqlite/jni/capi/ConfigSqllogCallback;)I
|
||||
* Signature: (Lorg/sqlite/jni/capi/ConfigSqlLogCallback;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1SQLLOG
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
@ -1052,10 +1052,10 @@ public final class CApi {
|
||||
);
|
||||
|
||||
/**
|
||||
Internal level of indirection for sqlite3_config(ConfigSqllogCallback).
|
||||
Internal level of indirection for sqlite3_config(ConfigSqlLogCallback).
|
||||
*/
|
||||
private static native int sqlite3_config__SQLLOG(
|
||||
@Nullable ConfigSqllogCallback logger
|
||||
@Nullable ConfigSqlLogCallback logger
|
||||
);
|
||||
|
||||
/**
|
||||
@ -1091,7 +1091,7 @@ public final class CApi {
|
||||
the rest of the library. This must not be called when any other
|
||||
library APIs are being called.
|
||||
*/
|
||||
public static int sqlite3_config( @Nullable ConfigSqllogCallback logger ){
|
||||
public static int sqlite3_config( @Nullable ConfigSqlLogCallback logger ){
|
||||
return sqlite3_config__SQLLOG(logger);
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ package org.sqlite.jni.capi;
|
||||
/**
|
||||
A callback for use with sqlite3_config().
|
||||
*/
|
||||
public interface ConfigSqllogCallback {
|
||||
public interface ConfigSqlLogCallback {
|
||||
/**
|
||||
Must function as described for a C-level callback for
|
||||
{@link CApi#sqlite3_config(ConfigSqllogCallback)}, with the slight signature change.
|
||||
{@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
|
||||
*/
|
||||
void call(sqlite3 db, String msg, int msgType );
|
||||
}
|
@ -2007,7 +2007,7 @@ public class Tester1 implements Runnable {
|
||||
|
||||
if( sqlLog ){
|
||||
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
|
||||
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
|
||||
final ConfigSqlLogCallback log = new ConfigSqlLogCallback() {
|
||||
@Override public void call(sqlite3 db, String msg, int op){
|
||||
switch(op){
|
||||
case 0: outln("Opening db: ",db); break;
|
||||
@ -2018,7 +2018,7 @@ public class Tester1 implements Runnable {
|
||||
};
|
||||
int rc = sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
rc = sqlite3_config( (ConfigSqllogCallback)null );
|
||||
rc = sqlite3_config( (ConfigSqlLogCallback)null );
|
||||
affirm( 0==rc );
|
||||
rc = sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
|
@ -209,6 +209,10 @@ public final class Sqlite implements AutoCloseable {
|
||||
public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS;
|
||||
public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER;
|
||||
|
||||
public static final int CONFIG_SINGLETHREAD = CApi.SQLITE_CONFIG_SINGLETHREAD;
|
||||
public static final int CONFIG_MULTITHREAD = CApi.SQLITE_CONFIG_MULTITHREAD;
|
||||
public static final int CONFIG_SERIALIZED = CApi.SQLITE_CONFIG_SERIALIZED;
|
||||
|
||||
public static final int UTF8 = CApi.SQLITE_UTF8;
|
||||
public static final int UTF16 = CApi.SQLITE_UTF16;
|
||||
public static final int UTF16LE = CApi.SQLITE_UTF16LE;
|
||||
@ -261,6 +265,32 @@ public final class Sqlite implements AutoCloseable {
|
||||
private static final java.util.Map<org.sqlite.jni.capi.sqlite3, Sqlite> nativeToWrapper
|
||||
= new java.util.HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
When any given thread is done using the SQLite library, calling
|
||||
this will free up any native-side resources which may be
|
||||
associated specifically with that thread. This is not strictly
|
||||
necessary, in particular in applications which only use SQLite
|
||||
from a single thread, but may help free some otherwise errant
|
||||
resources.
|
||||
|
||||
Calling into SQLite from a given thread after this has been
|
||||
called in that thread is harmless. The library will simply start
|
||||
to re-cache certain state for that thread.
|
||||
|
||||
Contrariwise, failing to call this will effectively leak a small
|
||||
amount of cached state for the thread, which may add up to
|
||||
significant amounts if the application uses SQLite from many
|
||||
threads.
|
||||
|
||||
This must never be called while actively using SQLite from this
|
||||
thread, e.g. from within a query loop or a callback which is
|
||||
operating on behalf of the library.
|
||||
*/
|
||||
static void uncacheThread(){
|
||||
CApi.sqlite3_java_uncache_thread();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the Sqlite object associated with the given sqlite3
|
||||
object, or null if there is no such mapping.
|
||||
@ -342,6 +372,9 @@ public final class Sqlite implements AutoCloseable {
|
||||
private static boolean hasNormalizeSql =
|
||||
compileOptionUsed("ENABLE_NORMALIZE");
|
||||
|
||||
private static boolean hasSqlLog =
|
||||
compileOptionUsed("ENABLE_SQLLOG");
|
||||
|
||||
/**
|
||||
Throws UnsupportedOperationException if check is false.
|
||||
flag is expected to be the name of an SQLITE_ENABLE_...
|
||||
@ -410,7 +443,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
new org.sqlite.jni.capi.OutputPointer.Int64();
|
||||
org.sqlite.jni.capi.OutputPointer.Int64 pHighwater =
|
||||
new org.sqlite.jni.capi.OutputPointer.Int64();
|
||||
checkRc2( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
|
||||
checkRcStatic( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
|
||||
final Status s = new Status();
|
||||
s.current = pCurrent.value;
|
||||
s.peak = pHighwater.value;
|
||||
@ -489,7 +522,7 @@ public final class Sqlite implements AutoCloseable {
|
||||
Like checkRc() but behaves as if that function were
|
||||
called with a null db object.
|
||||
*/
|
||||
private static void checkRc2(int rc){
|
||||
private static void checkRcStatic(int rc){
|
||||
if( 0!=rc ){
|
||||
if( CApi.SQLITE_NOMEM==rc ){
|
||||
throw new OutOfMemoryError();
|
||||
@ -1859,4 +1892,81 @@ public final class Sqlite implements AutoCloseable {
|
||||
return new Blob(this, out.take());
|
||||
}
|
||||
|
||||
/**
|
||||
Callback for use with libConfigLog().
|
||||
*/
|
||||
public interface ConfigLog {
|
||||
/**
|
||||
Must function as described for a C-level callback for
|
||||
sqlite3_config()'s SQLITE_CONFIG_LOG callback, with the slight
|
||||
signature change. Any exceptions thrown from this callback are
|
||||
necessarily suppressed.
|
||||
*/
|
||||
void call(int errCode, String msg);
|
||||
}
|
||||
|
||||
/**
|
||||
Analog to sqlite3_config() with the SQLITE_CONFIG_LOG option,
|
||||
this sets or (if log is null) clears the current logger.
|
||||
*/
|
||||
public static void libConfigLog(ConfigLog log){
|
||||
final org.sqlite.jni.capi.ConfigLogCallback l =
|
||||
null==log
|
||||
? null
|
||||
: new org.sqlite.jni.capi.ConfigLogCallback() {
|
||||
@Override public void call(int errCode, String msg){
|
||||
log.call(errCode, msg);
|
||||
}
|
||||
};
|
||||
checkRcStatic(CApi.sqlite3_config(l));
|
||||
}
|
||||
|
||||
/**
|
||||
Callback for use with libConfigSqlLog().
|
||||
*/
|
||||
public interface ConfigSqlLog {
|
||||
/**
|
||||
Must function as described for a C-level callback for
|
||||
sqlite3_config()'s SQLITE_CONFIG_SQLLOG callback, with the
|
||||
slight signature change. Any exceptions thrown from this
|
||||
callback are necessarily suppressed.
|
||||
*/
|
||||
void call(Sqlite db, String msg, int msgType);
|
||||
}
|
||||
|
||||
/**
|
||||
Analog to sqlite3_config() with the SQLITE_CONFIG_SQLLOG option,
|
||||
this sets or (if log is null) clears the current logger.
|
||||
|
||||
If SQLite is built without SQLITE_ENABLE_SQLLOG defined then this
|
||||
will throw an UnsupportedOperationException.
|
||||
*/
|
||||
public static void libConfigSqlLog(ConfigSqlLog log){
|
||||
Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_SQLLOG");
|
||||
final org.sqlite.jni.capi.ConfigSqlLogCallback l =
|
||||
null==log
|
||||
? null
|
||||
: new org.sqlite.jni.capi.ConfigSqlLogCallback() {
|
||||
@Override public void call(sqlite3 db, String msg, int msgType){
|
||||
try{
|
||||
log.call(fromNative(db), msg, msgType);
|
||||
}catch(Exception e){
|
||||
/* Suppressed */
|
||||
}
|
||||
}
|
||||
};
|
||||
checkRcStatic(CApi.sqlite3_config(l));
|
||||
}
|
||||
|
||||
/**
|
||||
Analog to the C-level sqlite3_config() with one of the
|
||||
SQLITE_CONFIG_... constants defined as CONFIG_... in this
|
||||
class. Throws on error, including passing of an unknown option or
|
||||
if a specified option is not supported by the underlying build of
|
||||
the SQLite library.
|
||||
*/
|
||||
public static void libConfigOp( int op ){
|
||||
checkRcStatic(CApi.sqlite3_config(op));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -762,9 +762,9 @@ public class Tester2 implements Runnable {
|
||||
affirm( newHook == oldHook );
|
||||
execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
|
||||
affirm( 5 == counter.value );
|
||||
hookResult.value = CApi.SQLITE_ERROR;
|
||||
hookResult.value = Sqlite.ERROR;
|
||||
int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
|
||||
affirm( CApi.SQLITE_CONSTRAINT_COMMITHOOK == rc );
|
||||
affirm( Sqlite.CONSTRAINT_COMMITHOOK == rc );
|
||||
affirm( 6 == counter.value );
|
||||
db.close();
|
||||
}
|
||||
@ -994,8 +994,7 @@ public class Tester2 implements Runnable {
|
||||
listErrors.add(e);
|
||||
}
|
||||
}finally{
|
||||
affirm( CApi.sqlite3_java_uncache_thread() );
|
||||
affirm( !CApi.sqlite3_java_uncache_thread() );
|
||||
Sqlite.uncacheThread();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1068,38 +1067,28 @@ public class Tester2 implements Runnable {
|
||||
|
||||
if( sqlLog ){
|
||||
if( Sqlite.compileOptionUsed("ENABLE_SQLLOG") ){
|
||||
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
|
||||
@Override public void call(sqlite3 db, String msg, int op){
|
||||
Sqlite.libConfigSqlLog( new Sqlite.ConfigSqlLog() {
|
||||
@Override public void call(Sqlite db, String msg, int op){
|
||||
switch(op){
|
||||
case 0: outln("Opening db: ",db); break;
|
||||
case 1: outln("SQL ",db,": ",msg); break;
|
||||
case 2: outln("Closing db: ",db); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
int rc = CApi.sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
rc = CApi.sqlite3_config( (ConfigSqllogCallback)null );
|
||||
affirm( 0==rc );
|
||||
rc = CApi.sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
}
|
||||
);
|
||||
}else{
|
||||
outln("WARNING: -sqllog is not active because library was built ",
|
||||
"without SQLITE_ENABLE_SQLLOG.");
|
||||
}
|
||||
}
|
||||
if( configLog ){
|
||||
final ConfigLogCallback log = new ConfigLogCallback() {
|
||||
Sqlite.libConfigLog( new Sqlite.ConfigLog() {
|
||||
@Override public void call(int code, String msg){
|
||||
outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
|
||||
outln("ConfigLog: ",Sqlite.errstr(code),": ", msg);
|
||||
};
|
||||
};
|
||||
int rc = CApi.sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
rc = CApi.sqlite3_config( (ConfigLogCallback)null );
|
||||
affirm( 0==rc );
|
||||
rc = CApi.sqlite3_config( log );
|
||||
affirm( 0==rc );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
quietMode = squelchTestOutput;
|
||||
@ -1132,39 +1121,16 @@ public class Tester2 implements Runnable {
|
||||
}
|
||||
|
||||
final long timeStart = System.currentTimeMillis();
|
||||
int nLoop = 0;
|
||||
switch( CApi.sqlite3_threadsafe() ){ /* Sanity checking */
|
||||
case 0:
|
||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
|
||||
"Could not switch to single-thread mode." );
|
||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
|
||||
"Could switch to multithread mode." );
|
||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
|
||||
"Could not switch to serialized threading mode." );
|
||||
outln("This is a single-threaded build. Not using threads.");
|
||||
nThread = 1;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
|
||||
"Could not switch to single-thread mode." );
|
||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
|
||||
"Could not switch to multithread mode." );
|
||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
|
||||
"Could not switch to serialized threading mode." );
|
||||
break;
|
||||
default:
|
||||
affirm( false, "Unhandled SQLITE_THREADSAFE value." );
|
||||
}
|
||||
outln("libversion_number: ",
|
||||
CApi.sqlite3_libversion_number(),"\n",
|
||||
CApi.sqlite3_libversion(),"\n",CApi.SQLITE_SOURCE_ID,"\n",
|
||||
Sqlite.libVersionNumber(),"\n",
|
||||
Sqlite.libVersion(),"\n",Sqlite.libSourceId(),"\n",
|
||||
"SQLITE_THREADSAFE=",CApi.sqlite3_threadsafe());
|
||||
final boolean showLoopCount = (nRepeat>1 && nThread>1);
|
||||
if( showLoopCount ){
|
||||
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
|
||||
}
|
||||
if( takeNaps ) outln("Napping between tests is enabled.");
|
||||
int nLoop = 0;
|
||||
for( int n = 0; n < nRepeat; ++n ){
|
||||
++nLoop;
|
||||
if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
|
||||
@ -1206,7 +1172,7 @@ public class Tester2 implements Runnable {
|
||||
if( doSomethingForDev ){
|
||||
CApi.sqlite3_jni_internal_details();
|
||||
}
|
||||
affirm( 0==CApi.sqlite3_release_memory(1) );
|
||||
affirm( 0==Sqlite.libReleaseMemory(1) );
|
||||
CApi.sqlite3_shutdown();
|
||||
int nMethods = 0;
|
||||
int nNatives = 0;
|
||||
|
Reference in New Issue
Block a user