1
0
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:
stephan
2023-11-15 04:55:38 +00:00
parent 253727b33d
commit d7ef0e8f87
9 changed files with 150 additions and 74 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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));
}
}

View File

@ -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;