1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Export sqlite3_(db_)free_memory() and sqlite3_table_column_metadata() to JNI. Further internals renaming for consistency and legibility.

FossilOrigin-Name: 7c86aa3400ed591d38c1828f366f4b5de97954c2b301919d3f06d9c2d3d7d1f2
This commit is contained in:
stephan
2023-08-31 14:57:01 +00:00
parent 3823208d5b
commit 0c2ba994d2
7 changed files with 319 additions and 177 deletions

View File

@ -217,7 +217,8 @@
/* /*
** Declares local var env = s3jni_env(). All JNI calls involve a ** Declares local var env = s3jni_env(). All JNI calls involve a
** JNIEnv somewhere, always named env, and many of our macros assume ** JNIEnv somewhere, always named env, and many of our macros assume
** env is in scope. ** env is in scope. Where it's not, but should be, use this to make it
** so.
*/ */
#define S3JniDeclLocal_env JNIEnv * const env = s3jni_env() #define S3JniDeclLocal_env JNIEnv * const env = s3jni_env()
@ -316,6 +317,7 @@ static const struct {
const S3JniNphRef sqlite3_stmt; const S3JniNphRef sqlite3_stmt;
const S3JniNphRef sqlite3_context; const S3JniNphRef sqlite3_context;
const S3JniNphRef sqlite3_value; const S3JniNphRef sqlite3_value;
const S3JniNphRef OutputPointer_Bool;
const S3JniNphRef OutputPointer_Int32; const S3JniNphRef OutputPointer_Int32;
const S3JniNphRef OutputPointer_Int64; const S3JniNphRef OutputPointer_Int64;
const S3JniNphRef OutputPointer_sqlite3; const S3JniNphRef OutputPointer_sqlite3;
@ -341,22 +343,23 @@ static const struct {
RefN(1, "sqlite3_stmt"), RefN(1, "sqlite3_stmt"),
RefN(2, "sqlite3_context"), RefN(2, "sqlite3_context"),
RefN(3, "sqlite3_value"), RefN(3, "sqlite3_value"),
RefO(4, "OutputPointer$Int32", "I"), RefO(4, "OutputPointer$Bool", "Z"),
RefO(5, "OutputPointer$Int64", "J"), RefO(5, "OutputPointer$Int32", "I"),
RefO(6, "OutputPointer$sqlite3", RefO(6, "OutputPointer$Int64", "J"),
RefO(7, "OutputPointer$sqlite3",
"Lorg/sqlite/jni/sqlite3;"), "Lorg/sqlite/jni/sqlite3;"),
RefO(7, "OutputPointer$sqlite3_stmt", RefO(8, "OutputPointer$sqlite3_stmt",
"Lorg/sqlite/jni/sqlite3_stmt;"), "Lorg/sqlite/jni/sqlite3_stmt;"),
RefO(8, "OutputPointer$sqlite3_value", RefO(9, "OutputPointer$sqlite3_value",
"Lorg/sqlite/jni/sqlite3_value;"), "Lorg/sqlite/jni/sqlite3_value;"),
#ifdef SQLITE_ENABLE_FTS5 #ifdef SQLITE_ENABLE_FTS5
RefO(9, "OutputPointer$String", "Ljava/lang/String;"), RefO(10, "OutputPointer$String", "Ljava/lang/String;"),
RefO(10, "OutputPointer$ByteArray", "[B"), RefO(11, "OutputPointer$ByteArray", "[B"),
RefN(11, "Fts5Context"), RefN(12, "Fts5Context"),
RefN(12, "Fts5ExtensionApi"), RefN(13, "Fts5ExtensionApi"),
RefN(13, "fts5_api"), RefN(14, "fts5_api"),
RefN(14, "fts5_tokenizer"), RefN(15, "fts5_tokenizer"),
RefN(15, "Fts5Tokenizer") RefN(16, "Fts5Tokenizer")
#endif #endif
#undef MkRef #undef MkRef
#undef RefN #undef RefN
@ -449,6 +452,9 @@ struct S3JniDb {
#endif #endif
S3JniDb * pNext /* Next entry in SJG.perDb.aFree */; S3JniDb * pNext /* Next entry in SJG.perDb.aFree */;
}; };
#define S3JniDb_clientdata_key "S3JniDb"
#define S3JniDb_from_clientdata(pDb) \
(pDb ? sqlite3_get_clientdata(pDb, S3JniDb_clientdata_key) : 0)
/* /*
** Cache for per-JNIEnv (i.e. per-thread) data. ** Cache for per-JNIEnv (i.e. per-thread) data.
@ -690,77 +696,77 @@ static void s3jni_incr( volatile unsigned int * const p ){
/* Helpers for working with specific mutexes. */ /* Helpers for working with specific mutexes. */
#if SQLITE_THREADSAFE #if SQLITE_THREADSAFE
#define S3JniMutex_Env_assertLocked \ #define S3JniEnv_mutex_assertLocked \
assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_assertLocker \ #define S3JniEnv_mutex_assertLocker \
assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_assertNotLocker \ #define S3JniEnv_mutex_assertNotLocker \
assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_enter \ #define S3JniEnv_mutex_enter \
S3JniMutex_Env_assertNotLocker; \ S3JniEnv_mutex_assertNotLocker; \
sqlite3_mutex_enter( SJG.envCache.mutex ); \ sqlite3_mutex_enter( SJG.envCache.mutex ); \
s3jni_incr(&SJG.metrics.nMutexEnv); \ s3jni_incr(&SJG.metrics.nMutexEnv); \
SJG.envCache.locker = env SJG.envCache.locker = env
#define S3JniMutex_Env_leave \ #define S3JniEnv_mutex_leave \
S3JniMutex_Env_assertLocker; \ S3JniEnv_mutex_assertLocker; \
SJG.envCache.locker = 0; \ SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex ) sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_Ext_enter \ #define S3JniAutoExt_mutex_enter \
sqlite3_mutex_enter( SJG.autoExt.mutex ); \ sqlite3_mutex_enter( SJG.autoExt.mutex ); \
SJG.autoExt.locker = env; \ SJG.autoExt.locker = env; \
s3jni_incr( &SJG.metrics.nMutexAutoExt ) s3jni_incr( &SJG.metrics.nMutexAutoExt )
#define S3JniMutex_Ext_leave \ #define S3JniAutoExt_mutex_leave \
assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ); \ assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ); \
sqlite3_mutex_leave( SJG.autoExt.mutex ) sqlite3_mutex_leave( SJG.autoExt.mutex )
#define S3JniMutex_Ext_assertLocker \ #define S3JniAutoExt_mutex_assertLocker \
assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ) assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" )
#define S3JniMutex_Global_enter \ #define S3JniGlobal_mutex_enter \
sqlite3_mutex_enter( SJG.mutex ); \ sqlite3_mutex_enter( SJG.mutex ); \
s3jni_incr(&SJG.metrics.nMutexGlobal); s3jni_incr(&SJG.metrics.nMutexGlobal);
#define S3JniMutex_Global_leave \ #define S3JniGlobal_mutex_leave \
sqlite3_mutex_leave( SJG.mutex ) sqlite3_mutex_leave( SJG.mutex )
#define S3JniMutex_Nph_enter \ #define S3JniNph_mutex_enter \
S3JniMutex_Env_assertNotLocker; \ S3JniEnv_mutex_assertNotLocker; \
sqlite3_mutex_enter( SJG.envCache.mutex ); \ sqlite3_mutex_enter( SJG.envCache.mutex ); \
s3jni_incr( &SJG.metrics.nMutexEnv2 ); \ s3jni_incr( &SJG.metrics.nMutexEnv2 ); \
SJG.envCache.locker = env SJG.envCache.locker = env
#define S3JniMutex_Nph_leave \ #define S3JniNph_mutex_leave \
S3JniMutex_Env_assertLocker; \ S3JniEnv_mutex_assertLocker; \
SJG.envCache.locker = 0; \ SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex ) sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_S3JniDb_assertLocker \ #define S3JniDb_mutex_assertLocker \
assert( (env) == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ) assert( (env) == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
#define S3JniMutex_S3JniDb_enter \ #define S3JniDb_mutex_enter \
sqlite3_mutex_enter( SJG.perDb.mutex ); \ sqlite3_mutex_enter( SJG.perDb.mutex ); \
assert( 0==SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \ assert( 0==SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \
s3jni_incr( &SJG.metrics.nMutexPerDb ); \ s3jni_incr( &SJG.metrics.nMutexPerDb ); \
SJG.perDb.locker = env; SJG.perDb.locker = env;
#define S3JniMutex_S3JniDb_leave \ #define S3JniDb_mutex_leave \
assert( env == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \ assert( env == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \
SJG.perDb.locker = 0; \ SJG.perDb.locker = 0; \
sqlite3_mutex_leave( SJG.perDb.mutex ) sqlite3_mutex_leave( SJG.perDb.mutex )
#else /* SQLITE_THREADSAFE==0 */ #else /* SQLITE_THREADSAFE==0 */
#define S3JniMutex_Env_assertLocked #define S3JniEnv_mutex_assertLocked
#define S3JniMutex_Env_assertLocker #define S3JniEnv_mutex_assertLocker
#define S3JniMutex_Env_assertNotLocker #define S3JniEnv_mutex_assertNotLocker
#define S3JniMutex_Env_enter #define S3JniEnv_mutex_enter
#define S3JniMutex_Env_leave #define S3JniEnv_mutex_leave
#define S3JniMutex_Ext_assertLocker #define S3JniAutoExt_mutex_assertLocker
#define S3JniMutex_Ext_enter #define S3JniAutoExt_mutex_enter
#define S3JniMutex_Ext_leave #define S3JniAutoExt_mutex_leave
#define S3JniMutex_Global_enter #define S3JniGlobal_mutex_enter
#define S3JniMutex_Global_leave #define S3JniGlobal_mutex_leave
#define S3JniMutex_Nph_enter #define S3JniNph_mutex_enter
#define S3JniMutex_Nph_leave #define S3JniNph_mutex_leave
#define S3JniMutex_S3JniDb_assertLocker #define S3JniDb_mutex_assertLocker
#define S3JniMutex_S3JniDb_enter #define S3JniDb_mutex_enter
#define S3JniMutex_S3JniDb_leave #define S3JniDb_mutex_leave
#endif #endif
/* Helpers for jstring and jbyteArray. */ /* Helpers for jstring and jbyteArray. */
@ -805,12 +811,12 @@ static JNIEnv * s3jni_env(void){
*/ */
static S3JniEnv * S3JniEnv__get(JNIEnv * const env){ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
struct S3JniEnv * row; struct S3JniEnv * row;
S3JniMutex_Env_enter; S3JniEnv_mutex_enter;
row = SJG.envCache.aHead; row = SJG.envCache.aHead;
for( ; row; row = row->pNext ){ for( ; row; row = row->pNext ){
if( row->env == env ){ if( row->env == env ){
s3jni_incr( &SJG.metrics.nEnvHit ); s3jni_incr( &SJG.metrics.nEnvHit );
S3JniMutex_Env_leave; S3JniEnv_mutex_leave;
return row; return row;
} }
} }
@ -827,7 +833,7 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
SJG.envCache.aHead = row; SJG.envCache.aHead = row;
row->env = env; row->env = env;
S3JniMutex_Env_leave; S3JniEnv_mutex_leave;
return row; return row;
} }
@ -1038,12 +1044,12 @@ static int s3jni__db_exception(JNIEnv * const env, S3JniDb * const ps,
if( ex ){ if( ex ){
char * zMsg; char * zMsg;
S3JniExceptionClear; S3JniExceptionClear;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
zMsg = s3jni_exception_error_msg(env, ex); zMsg = s3jni_exception_error_msg(env, ex);
s3jni_db_error(ps->pDb, errCode, zMsg ? zMsg : zDfltMsg); s3jni_db_error(ps->pDb, errCode, zMsg ? zMsg : zDfltMsg);
sqlite3_free(zMsg); sqlite3_free(zMsg);
S3JniUnrefLocal(ex); S3JniUnrefLocal(ex);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
return errCode; return errCode;
} }
@ -1097,12 +1103,12 @@ static void s3jni__call_xDestroy(JNIEnv * const env, jobject jObj){
*/ */
static void S3JniHook__localdup( JNIEnv * const env, S3JniHook const * const src, static void S3JniHook__localdup( JNIEnv * const env, S3JniHook const * const src,
S3JniHook * const dest ){ S3JniHook * const dest ){
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
*dest = *src; *dest = *src;
if(src->jObj) dest->jObj = S3JniRefLocal(src->jObj); if(src->jObj) dest->jObj = S3JniRefLocal(src->jObj);
if(src->jExtra) dest->jExtra = S3JniRefLocal(src->jExtra); if(src->jExtra) dest->jExtra = S3JniRefLocal(src->jExtra);
dest->doXDestroy = 0; dest->doXDestroy = 0;
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
#define S3JniHook_localdup(src,dest) S3JniHook__localdup(env,src,dest) #define S3JniHook_localdup(src,dest) S3JniHook__localdup(env,src,dest)
@ -1140,14 +1146,14 @@ static void S3JniHook__unref(JNIEnv * const env, S3JniHook * const s){
*/ */
static S3JniHook *S3JniHook__alloc(JNIEnv * const env){ static S3JniHook *S3JniHook__alloc(JNIEnv * const env){
S3JniHook * p = 0; S3JniHook * p = 0;
S3JniMutex_Global_enter; S3JniGlobal_mutex_enter;
if( SJG.hooks.aFree ){ if( SJG.hooks.aFree ){
p = SJG.hooks.aFree; p = SJG.hooks.aFree;
SJG.hooks.aFree = p->pNext; SJG.hooks.aFree = p->pNext;
p->pNext = 0; p->pNext = 0;
s3jni_incr(&SJG.metrics.nHookRecycled); s3jni_incr(&SJG.metrics.nHookRecycled);
} }
S3JniMutex_Global_leave; S3JniGlobal_mutex_leave;
if( 0==p ){ if( 0==p ){
p = s3jni_malloc(sizeof(S3JniHook)); p = s3jni_malloc(sizeof(S3JniHook));
if( p ){ if( p ){
@ -1169,10 +1175,10 @@ static void S3JniHook__free(JNIEnv * const env, S3JniHook * const p){
if(p){ if(p){
assert( !p->pNext ); assert( !p->pNext );
S3JniHook_unref(p); S3JniHook_unref(p);
S3JniMutex_Global_enter; S3JniGlobal_mutex_enter;
p->pNext = SJG.hooks.aFree; p->pNext = SJG.hooks.aFree;
SJG.hooks.aFree = p; SJG.hooks.aFree = p;
S3JniMutex_Global_leave; S3JniGlobal_mutex_leave;
} }
} }
#define S3JniHook_free(hook) S3JniHook__free(env, hook) #define S3JniHook_free(hook) S3JniHook__free(env, hook)
@ -1197,7 +1203,7 @@ static void S3JniHook__free_unlocked(JNIEnv * const env, S3JniHook * const p){
** s->pNext and s->pPrev before calling this, as this clears them. ** s->pNext and s->pPrev before calling this, as this clears them.
*/ */
static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
S3JniMutex_S3JniDb_assertLocker; S3JniDb_mutex_assertLocker;
sqlite3_free( s->zMainDbName ); sqlite3_free( s->zMainDbName );
#define UNHOOK(MEMBER) \ #define UNHOOK(MEMBER) \
S3JniHook_unref(&s->hooks.MEMBER) S3JniHook_unref(&s->hooks.MEMBER)
@ -1223,7 +1229,7 @@ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
*/ */
static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){ static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
assert( s ); assert( s );
S3JniMutex_S3JniDb_assertLocker; S3JniDb_mutex_assertLocker;
if( s ){ if( s ){
S3JniDb_clear(env, s); S3JniDb_clear(env, s);
s->pNext = SJG.perDb.aFree; s->pNext = SJG.perDb.aFree;
@ -1233,9 +1239,9 @@ static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
#define S3JniDb_set_aside_unlocked(JniDb) S3JniDb__set_aside_unlocked(env, JniDb) #define S3JniDb_set_aside_unlocked(JniDb) S3JniDb__set_aside_unlocked(env, JniDb)
static void S3JniDb__set_aside(JNIEnv * const env, S3JniDb * const s){ static void S3JniDb__set_aside(JNIEnv * const env, S3JniDb * const s){
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
S3JniDb_set_aside_unlocked(s); S3JniDb_set_aside_unlocked(s);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
#define S3JniDb_set_aside(JNIDB) S3JniDb__set_aside(env, JNIDB) #define S3JniDb_set_aside(JNIDB) S3JniDb__set_aside(env, JNIDB)
@ -1250,7 +1256,7 @@ static void S3JniDb__set_aside(JNIEnv * const env, S3JniDb * const s){
static int S3JniEnv_uncache(JNIEnv * const env){ static int S3JniEnv_uncache(JNIEnv * const env){
struct S3JniEnv * row; struct S3JniEnv * row;
struct S3JniEnv * pPrev = 0; struct S3JniEnv * pPrev = 0;
S3JniMutex_Env_assertLocked; S3JniEnv_mutex_assertLocked;
row = SJG.envCache.aHead; row = SJG.envCache.aHead;
for( ; row; pPrev = row, row = row->pNext ){ for( ; row; pPrev = row, row = row->pNext ){
if( row->env == env ){ if( row->env == env ){
@ -1281,7 +1287,7 @@ static int S3JniEnv_uncache(JNIEnv * const env){
** **
** It is up to the caller to populate the other members of the ** It is up to the caller to populate the other members of the
** returned object if needed, taking care to lock the modification ** returned object if needed, taking care to lock the modification
** with S3JniMutex_Nph_enter/leave. ** with S3JniNph_mutex_enter/leave.
** **
** This simple cache catches >99% of searches in the current ** This simple cache catches >99% of searches in the current
** (2023-07-31) tests. ** (2023-07-31) tests.
@ -1308,7 +1314,7 @@ static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3JniNphRef const* p
assert( pRef->index>=0 assert( pRef->index>=0
&& (pRef->index < (sizeof(S3JniNphRefs) / sizeof(S3JniNphRef))) ); && (pRef->index < (sizeof(S3JniNphRefs) / sizeof(S3JniNphRef))) );
if( !pNC->pRef ){ if( !pNC->pRef ){
S3JniMutex_Nph_enter; S3JniNph_mutex_enter;
if( !pNC->pRef ){ if( !pNC->pRef ){
jclass const klazz = (*env)->FindClass(env, pRef->zName); jclass const klazz = (*env)->FindClass(env, pRef->zName);
S3JniExceptionIsFatal("FindClass() unexpectedly threw"); S3JniExceptionIsFatal("FindClass() unexpectedly threw");
@ -1317,7 +1323,7 @@ static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3JniNphRef const* p
/* Must come last to avoid a race condition where pNC->klass /* Must come last to avoid a race condition where pNC->klass
can be NULL after this function returns. */; can be NULL after this function returns. */;
} }
S3JniMutex_Nph_leave; S3JniNph_mutex_leave;
} }
assert( pNC->klazz ); assert( pNC->klazz );
return pNC; return pNC;
@ -1341,14 +1347,14 @@ static jfieldID s3jni_nphop_field(JNIEnv * const env, S3JniNphRef const* pRef){
S3JniNphClass * const pNC = S3JniGlobal_nph(pRef); S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
if( !pNC->fidValue ){ if( !pNC->fidValue ){
S3JniMutex_Nph_enter; S3JniNph_mutex_enter;
if( !pNC->fidValue ){ if( !pNC->fidValue ){
pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz, pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz,
pRef->zMember, pRef->zTypeSig); pRef->zMember, pRef->zTypeSig);
S3JniExceptionIsFatal("Code maintenance required: missing " S3JniExceptionIsFatal("Code maintenance required: missing "
"required S3JniNphClass::fidValue."); "required S3JniNphClass::fidValue.");
} }
S3JniMutex_Nph_leave; S3JniNph_mutex_leave;
} }
assert( pNC->fidValue ); assert( pNC->fidValue );
return pNC->fidValue; return pNC->fidValue;
@ -1415,9 +1421,9 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject pObj,
*/ */
static sqlite3* PtrGet__sqlite3_lock(JNIEnv * const env, jobject jObj){ static sqlite3* PtrGet__sqlite3_lock(JNIEnv * const env, jobject jObj){
sqlite3 *rv; sqlite3 *rv;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
rv = PtrGet_sqlite3(jObj); rv = PtrGet_sqlite3(jObj);
if( !rv ){ S3JniMutex_S3JniDb_leave; } if( !rv ){ S3JniDb_mutex_leave; }
return rv; return rv;
} }
#undef PtrGet_sqlite3 #undef PtrGet_sqlite3
@ -1431,14 +1437,16 @@ static sqlite3* PtrGet__sqlite3_lock(JNIEnv * const env, jobject jObj){
** associated with jDb via NativePointerHolder_set(). ** associated with jDb via NativePointerHolder_set().
*/ */
static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){
S3JniDb * rv; S3JniDb * rv = 0;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
if( SJG.perDb.aFree ){ if( SJG.perDb.aFree ){
rv = SJG.perDb.aFree; rv = SJG.perDb.aFree;
SJG.perDb.aFree = rv->pNext; SJG.perDb.aFree = rv->pNext;
rv->pNext = 0; rv->pNext = 0;
s3jni_incr( &SJG.metrics.nPdbRecycled ); s3jni_incr( &SJG.metrics.nPdbRecycled );
}else{ }
S3JniDb_mutex_leave;
if( 0==rv ){
rv = s3jni_malloc( sizeof(S3JniDb)); rv = s3jni_malloc( sizeof(S3JniDb));
if( rv ){ if( rv ){
s3jni_incr( &SJG.metrics.nPdbAlloc ); s3jni_incr( &SJG.metrics.nPdbAlloc );
@ -1448,16 +1456,9 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){
memset(rv, 0, sizeof(S3JniDb)); memset(rv, 0, sizeof(S3JniDb));
rv->jDb = S3JniRefGlobal(jDb); rv->jDb = S3JniRefGlobal(jDb);
} }
S3JniMutex_S3JniDb_leave;
return rv; return rv;
} }
#define S3JniDb_clientdata_key "S3JniDb"
/* Short-lived code consolidator. */
#define S3JniDb_search \
s = pDb ? sqlite3_get_clientdata(pDb, S3JniDb_clientdata_key) : 0
/* /*
** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3 ** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3
** object, or NULL if jDb is NULL, no pointer can be extracted ** object, or NULL if jDb is NULL, no pointer can be extracted
@ -1468,24 +1469,20 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){
static S3JniDb * S3JniDb__from_java(JNIEnv * const env, jobject jDb){ static S3JniDb * S3JniDb__from_java(JNIEnv * const env, jobject jDb){
S3JniDb * s = 0; S3JniDb * s = 0;
sqlite3 * pDb = 0; sqlite3 * pDb = 0;
S3JniDb_mutex_enter;
S3JniMutex_S3JniDb_enter;
if( jDb ) pDb = PtrGet_sqlite3(jDb); if( jDb ) pDb = PtrGet_sqlite3(jDb);
S3JniDb_search; s = S3JniDb_from_clientdata(pDb);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return s; return s;
} }
#define S3JniDb_from_java(jObject) S3JniDb__from_java(env,(jObject)) #define S3JniDb_from_java(jObject) S3JniDb__from_java(env,(jObject))
static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){ static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
S3JniDb * s = 0;
sqlite3 * pDb = 0; sqlite3 * pDb = 0;
S3JniDb_mutex_assertLocker;
S3JniMutex_S3JniDb_assertLocker;
if( jDb ) pDb = PtrGet_sqlite3(jDb); if( jDb ) pDb = PtrGet_sqlite3(jDb);
S3JniDb_search; return S3JniDb_from_clientdata(pDb);
return s;
} }
#define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB)) #define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB))
@ -1493,29 +1490,18 @@ static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
** S3JniDb finalizer for use with sqlite3_set_clientdata(). ** S3JniDb finalizer for use with sqlite3_set_clientdata().
*/ */
static void S3JniDb_xDestroy(void *p){ static void S3JniDb_xDestroy(void *p){
S3JniDb * ps = p;
S3JniDeclLocal_env; S3JniDeclLocal_env;
S3JniDb * const ps = p;
assert( !ps->pNext ); assert( !ps->pNext );
S3JniDb_set_aside(ps); S3JniDb_set_aside(ps);
} }
/* /*
** Returns the S3JniDb object for the sqlite3 object, or NULL if pDb ** Evaluates to the S3JniDb object for the given sqlite3 object, or
** is NULL, or no matching entry ** NULL if pDb is NULL or was not initialized via the JNI interfaces.
** can be found.
**
** Requires locking the S3JniDb mutex.
*/ */
static S3JniDb * S3JniDb__from_c(JNIEnv * const env, sqlite3 *pDb){ #define S3JniDb_from_c(sqlite3Ptr) \
S3JniDb * s = 0; ((sqlite3Ptr) ? S3JniDb_from_clientdata(sqlite3Ptr) : 0)
S3JniMutex_S3JniDb_enter;
S3JniDb_search;
S3JniMutex_S3JniDb_leave;
return s;
}
#define S3JniDb_from_c(sqlite3Ptr) S3JniDb__from_c(env,(sqlite3Ptr))
/* /*
** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out ** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out
@ -1534,7 +1520,7 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
jobject const jAutoExt){ jobject const jAutoExt){
jclass const klazz = (*env)->GetObjectClass(env, jAutoExt); jclass const klazz = (*env)->GetObjectClass(env, jAutoExt);
S3JniMutex_Ext_assertLocker; S3JniAutoExt_mutex_assertLocker;
*ax = S3JniHook_empty; *ax = S3JniHook_empty;
ax->midCallback = (*env)->GetMethodID(env, klazz, "call", ax->midCallback = (*env)->GetMethodID(env, klazz, "call",
"(Lorg/sqlite/jni/sqlite3;)I"); "(Lorg/sqlite/jni/sqlite3;)I");
@ -1548,6 +1534,18 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
return 0; return 0;
} }
/*
** Sets the value property of the OutputPointer.Bool jOut object to
** v.
*/
static void OutputPointer_set_Bool(JNIEnv * const env, jobject const jOut,
int v){
(*env)->SetBooleanField(env, jOut, s3jni_nphop_field(
env, &S3JniNphRefs.OutputPointer_Bool
), v ? JNI_TRUE : JNI_FALSE );
S3JniExceptionIsFatal("Cannot set OutputPointer.Bool.value");
}
/* /*
** Sets the value property of the OutputPointer.Int32 jOut object to ** Sets the value property of the OutputPointer.Int32 jOut object to
** v. ** v.
@ -1624,6 +1622,7 @@ static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_ByteArray, jOut, v); OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_ByteArray, jOut, v);
} }
#endif #endif
#endif /* SQLITE_ENABLE_FTS5 */
/* /*
** Sets the value property of the OutputPointer.String jOut object to ** Sets the value property of the OutputPointer.String jOut object to
@ -1633,7 +1632,6 @@ static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
jstring const v){ jstring const v){
OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_String, jOut, v); OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_String, jOut, v);
} }
#endif /* SQLITE_ENABLE_FTS5 */
/* /*
** Returns true if eTextRep is a valid sqlite3 encoding constant, else ** Returns true if eTextRep is a valid sqlite3 encoding constant, else
@ -1681,12 +1679,12 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, S3JniNphRef co
jobject rv = 0; jobject rv = 0;
S3JniNphClass * const pNC = S3JniGlobal_nph(pRef); S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
if( !pNC->midCtor ){ if( !pNC->midCtor ){
S3JniMutex_Nph_enter; S3JniNph_mutex_enter;
if( !pNC->midCtor ){ if( !pNC->midCtor ){
pNC->midCtor = (*env)->GetMethodID(env, pNC->klazz, "<init>", "()V"); pNC->midCtor = (*env)->GetMethodID(env, pNC->klazz, "<init>", "()V");
S3JniExceptionIsFatal("Cannot find constructor for class."); S3JniExceptionIsFatal("Cannot find constructor for class.");
} }
S3JniMutex_Nph_leave; S3JniNph_mutex_leave;
} }
rv = (*env)->NewObject(env, pNC->klazz, pNC->midCtor); rv = (*env)->NewObject(env, pNC->klazz, pNC->midCtor);
S3JniExceptionIsFatal("No-arg constructor threw."); S3JniExceptionIsFatal("No-arg constructor threw.");
@ -1728,7 +1726,7 @@ typedef void (*udf_xFinal_f)(sqlite3_context*);
static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
S3JniUdf * s = 0; S3JniUdf * s = 0;
S3JniMutex_Global_enter; S3JniGlobal_mutex_enter;
s3jni_incr(&SJG.metrics.nMutexUdf); s3jni_incr(&SJG.metrics.nMutexUdf);
if( SJG.udf.aFree ){ if( SJG.udf.aFree ){
s = SJG.udf.aFree; s = SJG.udf.aFree;
@ -1736,7 +1734,7 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
s->pNext = 0; s->pNext = 0;
s3jni_incr(&SJG.metrics.nUdfRecycled); s3jni_incr(&SJG.metrics.nUdfRecycled);
} }
S3JniMutex_Global_leave; S3JniGlobal_mutex_leave;
if( !s ){ if( !s ){
s = s3jni_malloc( sizeof(*s)); s = s3jni_malloc( sizeof(*s));
s3jni_incr(&SJG.metrics.nUdfAlloc); s3jni_incr(&SJG.metrics.nUdfAlloc);
@ -1790,10 +1788,10 @@ static void S3JniUdf_free(JNIEnv * const env, S3JniUdf * const s,
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
} }
if( cacheIt ){ if( cacheIt ){
S3JniMutex_Global_enter; S3JniGlobal_mutex_enter;
s->pNext = S3JniGlobal.udf.aFree; s->pNext = S3JniGlobal.udf.aFree;
S3JniGlobal.udf.aFree = s; S3JniGlobal.udf.aFree = s;
S3JniMutex_Global_leave; S3JniGlobal_mutex_leave;
}else{ }else{
sqlite3_free( s ); sqlite3_free( s );
} }
@ -2060,6 +2058,7 @@ WRAP_INT_DB(1preupdate_1blobwrite, sqlite3_preupdate_blobwrite)
WRAP_INT_DB(1preupdate_1count, sqlite3_preupdate_count) WRAP_INT_DB(1preupdate_1count, sqlite3_preupdate_count)
WRAP_INT_DB(1preupdate_1depth, sqlite3_preupdate_depth) WRAP_INT_DB(1preupdate_1depth, sqlite3_preupdate_depth)
#endif #endif
WRAP_INT_INT(1release_1memory, sqlite3_release_memory)
WRAP_INT_INT(1sleep, sqlite3_sleep) WRAP_INT_INT(1sleep, sqlite3_sleep)
WRAP_MUTF8_VOID(1sourceid, sqlite3_sourceid) WRAP_MUTF8_VOID(1sourceid, sqlite3_sourceid)
WRAP_INT_VOID(1threadsafe, sqlite3_threadsafe) WRAP_INT_VOID(1threadsafe, sqlite3_threadsafe)
@ -2124,7 +2123,8 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
return rc; return rc;
} }
NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb) NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb)
/* As of here, the Java/C connection is complete */; /* As of here, the Java/C connection is complete except for the
(temporary) lack of finalizer for the ps object. */;
ps->pDb = pDb; ps->pDb = pDb;
for( i = 0; go && 0==rc; ++i ){ for( i = 0; go && 0==rc; ++i ){
S3JniAutoExtension ax = {0,0} S3JniAutoExtension ax = {0,0}
@ -2132,14 +2132,14 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
** local reference to it, to avoid a race condition with another ** local reference to it, to avoid a race condition with another
** thread manipulating the list during the call and invaliding ** thread manipulating the list during the call and invaliding
** what ax points to. */; ** what ax points to. */;
S3JniMutex_Ext_enter; S3JniAutoExt_mutex_enter;
if( i >= SJG.autoExt.nExt ){ if( i >= SJG.autoExt.nExt ){
go = 0; go = 0;
}else{ }else{
ax.jObj = S3JniRefLocal(SJG.autoExt.aExt[i].jObj); ax.jObj = S3JniRefLocal(SJG.autoExt.aExt[i].jObj);
ax.midCallback = SJG.autoExt.aExt[i].midCallback; ax.midCallback = SJG.autoExt.aExt[i].midCallback;
} }
S3JniMutex_Ext_leave; S3JniAutoExt_mutex_leave;
if( ax.jObj ){ if( ax.jObj ){
rc = (*env)->CallIntMethod(env, ax.jObj, ax.midCallback, ps->jDb); rc = (*env)->CallIntMethod(env, ax.jObj, ax.midCallback, ps->jDb);
S3JniUnrefLocal(ax.jObj); S3JniUnrefLocal(ax.jObj);
@ -2166,13 +2166,13 @@ S3JniApi(sqlite3_auto_extension(),jint,1auto_1extension)(
int rc = 0; int rc = 0;
if( !jAutoExt ) return SQLITE_MISUSE; if( !jAutoExt ) return SQLITE_MISUSE;
S3JniMutex_Ext_enter; S3JniAutoExt_mutex_enter;
for( i = 0; i < SJG.autoExt.nExt; ++i ){ for( i = 0; i < SJG.autoExt.nExt; ++i ){
/* Look for a match. */ /* Look for a match. */
ax = &SJG.autoExt.aExt[i]; ax = &SJG.autoExt.aExt[i];
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
/* same object, so this is a no-op. */ /* same object, so this is a no-op. */
S3JniMutex_Ext_leave; S3JniAutoExt_mutex_leave;
return 0; return 0;
} }
} }
@ -2215,7 +2215,7 @@ S3JniApi(sqlite3_auto_extension(),jint,1auto_1extension)(
++SJG.autoExt.nExt; ++SJG.autoExt.nExt;
} }
} }
S3JniMutex_Ext_leave; S3JniAutoExt_mutex_leave;
return rc; return rc;
} }
@ -2359,7 +2359,7 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
int rc = 0; int rc = 0;
if( !ps ) return (jint)SQLITE_MISUSE; if( !ps ) return (jint)SQLITE_MISUSE;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
if( jBusy ){ if( jBusy ){
if( pHook->jObj && (*env)->IsSameObject(env, pHook->jObj, jBusy) ){ if( pHook->jObj && (*env)->IsSameObject(env, pHook->jObj, jBusy) ){
/* Same object - this is a no-op. */ /* Same object - this is a no-op. */
@ -2391,7 +2391,7 @@ S3JniApi(sqlite3_busy_handler(),jint,1busy_1handler)(
} }
} }
S3JniHook_unref(&hook); S3JniHook_unref(&hook);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return rc; return rc;
} }
@ -2401,10 +2401,10 @@ S3JniApi(sqlite3_busy_timeout(),jint,1busy_1timeout)(
S3JniDb * const ps = S3JniDb_from_java(jDb); S3JniDb * const ps = S3JniDb_from_java(jDb);
int rc = SQLITE_MISUSE; int rc = SQLITE_MISUSE;
if( ps ){ if( ps ){
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
S3JniHook_unref(&ps->hooks.busyHandler); S3JniHook_unref(&ps->hooks.busyHandler);
rc = sqlite3_busy_timeout(ps->pDb, (int)ms); rc = sqlite3_busy_timeout(ps->pDb, (int)ms);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
return rc; return rc;
} }
@ -2415,7 +2415,7 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
S3JniAutoExtension * ax; S3JniAutoExtension * ax;
jboolean rc = JNI_FALSE; jboolean rc = JNI_FALSE;
int i; int i;
S3JniMutex_Ext_enter; S3JniAutoExt_mutex_enter;
/* This algo mirrors the one in the core. */ /* This algo mirrors the one in the core. */
for( i = SJG.autoExt.nExt-1; i >= 0; --i ){ for( i = SJG.autoExt.nExt-1; i >= 0; --i ){
ax = &SJG.autoExt.aExt[i]; ax = &SJG.autoExt.aExt[i];
@ -2430,7 +2430,7 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
break; break;
} }
} }
S3JniMutex_Ext_leave; S3JniAutoExt_mutex_leave;
return rc; return rc;
} }
@ -2513,10 +2513,10 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
S3JniCollationNeeded * pHook; S3JniCollationNeeded * pHook;
int rc = 0; int rc = 0;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
ps = S3JniDb_from_java_unlocked(jDb); ps = S3JniDb_from_java_unlocked(jDb);
if( !ps ){ if( !ps ){
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
pHook = &ps->hooks.collationNeeded; pHook = &ps->hooks.collationNeeded;
@ -2548,7 +2548,7 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
} }
} }
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return rc; return rc;
} }
@ -2655,11 +2655,11 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
jobject pOld = 0; jobject pOld = 0;
S3JniHook * pHook; S3JniHook * pHook;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
ps = S3JniDb_from_java_unlocked(jDb); ps = S3JniDb_from_java_unlocked(jDb);
if( !ps ){ if( !ps ){
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0); s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return 0; return 0;
} }
pHook = isCommit ? &ps->hooks.commit : &ps->hooks.rollback; pHook = isCommit ? &ps->hooks.commit : &ps->hooks.rollback;
@ -2699,7 +2699,7 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
} }
} }
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return pOld; return pOld;
} }
@ -2791,7 +2791,7 @@ S3JniApi(sqlite3_config() /* for SQLLOG */,
S3JniHook * const pHook = &SJG.hooks.sqllog; S3JniHook * const pHook = &SJG.hooks.sqllog;
int rc = 0; int rc = 0;
S3JniMutex_Global_enter; S3JniGlobal_mutex_enter;
if( !jLog ){ if( !jLog ){
rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 ); rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 );
if( 0==rc ){ if( 0==rc ){
@ -2818,7 +2818,7 @@ S3JniApi(sqlite3_config() /* for SQLLOG */,
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
} }
S3JniMutex_Global_leave; S3JniGlobal_mutex_leave;
return rc; return rc;
#endif #endif
} }
@ -2878,7 +2878,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
int rc; int rc;
S3JniDb * ps; S3JniDb * ps;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
ps = S3JniDb_from_java_unlocked(jDb); ps = S3JniDb_from_java_unlocked(jDb);
if( !ps ){ if( !ps ){
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
@ -2912,7 +2912,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
sqlite3_free(zName); sqlite3_free(zName);
} }
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return (jint)rc; return (jint)rc;
} }
@ -3009,7 +3009,7 @@ S3JniApi(sqlite3_db_config() /*for MAINDBNAME*/,
switch( (ps && jStr) ? op : 0 ){ switch( (ps && jStr) ? op : 0 ){
case SQLITE_DBCONFIG_MAINDBNAME: case SQLITE_DBCONFIG_MAINDBNAME:
S3JniMutex_S3JniDb_enter S3JniDb_mutex_enter
/* Protect against a race in modifying/freeing /* Protect against a race in modifying/freeing
ps->zMainDbName. */; ps->zMainDbName. */;
zStr = s3jni_jstring_to_utf8( jStr, 0); zStr = s3jni_jstring_to_utf8( jStr, 0);
@ -3024,7 +3024,7 @@ S3JniApi(sqlite3_db_config() /*for MAINDBNAME*/,
}else{ }else{
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
break; break;
default: default:
rc = SQLITE_MISUSE; rc = SQLITE_MISUSE;
@ -3089,6 +3089,12 @@ JniDecl(jint,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPoint
); );
} }
S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)(
JniArgsEnvClass, jobject jDb
){
sqlite3 * const pDb = PtrGet_sqlite3(jDb);
return pDb ? sqlite3_db_release_memory(pDb) : SQLITE_MISUSE;
}
S3JniApi(sqlite3_db_status(),jint,1db_1status)( S3JniApi(sqlite3_db_status(),jint,1db_1status)(
JniArgsEnvClass, jobject jDb, jint op, jobject jOutCurrent, JniArgsEnvClass, jobject jDb, jint op, jobject jOutCurrent,
@ -3197,9 +3203,9 @@ S3JniApi(sqlite3_is_interrupted(),jboolean,1is_1interrupted)(
*/ */
JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){ JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
int rc; int rc;
S3JniMutex_Env_enter; S3JniEnv_mutex_enter;
rc = S3JniEnv_uncache(env); rc = S3JniEnv_uncache(env);
S3JniMutex_Env_leave; S3JniEnv_mutex_leave;
return rc ? JNI_TRUE : JNI_FALSE; return rc ? JNI_TRUE : JNI_FALSE;
} }
@ -3278,8 +3284,8 @@ static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc,
&& "Set up via s3jni_run_java_auto_extensions()" ); && "Set up via s3jni_run_java_auto_extensions()" );
} }
rc = sqlite3_set_clientdata(ps->pDb, S3JniDb_clientdata_key, rc = sqlite3_set_clientdata(ps->pDb, S3JniDb_clientdata_key,
ps, S3JniDb_xDestroy); ps, S3JniDb_xDestroy)
/* As of here, the Java/C connection is complete */ /* As of here, the Java/C connection is complete */;
}else{ }else{
S3JniDb_set_aside(ps); S3JniDb_set_aside(ps);
ps = 0; ps = 0;
@ -3507,7 +3513,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jobject jDb, jobjec
S3JniHook * pHook; S3JniHook * pHook;
if( !ps ) return 0; if( !ps ) return 0;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
pHook = isPre ? pHook = isPre ?
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
&ps->hooks.preUpdate &ps->hooks.preUpdate
@ -3567,7 +3573,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jobject jDb, jobjec
} }
} }
end: end:
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return pOld; return pOld;
} }
@ -3648,7 +3654,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
S3JniHook * const pHook = ps ? &ps->hooks.progress : 0; S3JniHook * const pHook = ps ? &ps->hooks.progress : 0;
if( !ps ) return; if( !ps ) return;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
if( n<1 || !jProgress ){ if( n<1 || !jProgress ){
S3JniHook_unref(pHook); S3JniHook_unref(pHook);
sqlite3_progress_handler(ps->pDb, 0, 0, 0); sqlite3_progress_handler(ps->pDb, 0, 0, 0);
@ -3668,7 +3674,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
sqlite3_progress_handler(ps->pDb, (int)n, s3jni_progress_handler_impl, ps); sqlite3_progress_handler(ps->pDb, (int)n, s3jni_progress_handler_impl, ps);
} }
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
S3JniApi(sqlite3_reset(),jint,1reset)( S3JniApi(sqlite3_reset(),jint,1reset)(
@ -3681,12 +3687,12 @@ S3JniApi(sqlite3_reset(),jint,1reset)(
/* Clears all entries from S3JniGlobal.autoExt. */ /* Clears all entries from S3JniGlobal.autoExt. */
static void s3jni_reset_auto_extension(JNIEnv *env){ static void s3jni_reset_auto_extension(JNIEnv *env){
int i; int i;
S3JniMutex_Ext_enter; S3JniAutoExt_mutex_enter;
for( i = 0; i < SJG.autoExt.nExt; ++i ){ for( i = 0; i < SJG.autoExt.nExt; ++i ){
S3JniAutoExtension_clear( &SJG.autoExt.aExt[i] ); S3JniAutoExtension_clear( &SJG.autoExt.aExt[i] );
} }
SJG.autoExt.nExt = 0; SJG.autoExt.nExt = 0;
S3JniMutex_Ext_leave; S3JniAutoExt_mutex_leave;
} }
S3JniApi(sqlite3_reset_auto_extension(),void,1reset_1auto_1extension)( S3JniApi(sqlite3_reset_auto_extension(),void,1reset_1auto_1extension)(
@ -3948,7 +3954,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
int rc = 0; int rc = 0;
if( !ps ) return SQLITE_MISUSE; if( !ps ) return SQLITE_MISUSE;
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
if( !jHook ){ if( !jHook ){
S3JniHook_unref(pHook); S3JniHook_unref(pHook);
rc = sqlite3_set_authorizer( ps->pDb, 0, 0 ); rc = sqlite3_set_authorizer( ps->pDb, 0, 0 );
@ -3957,7 +3963,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
if( pHook->jObj ){ if( pHook->jObj ){
if( (*env)->IsSameObject(env, pHook->jObj, jHook) ){ if( (*env)->IsSameObject(env, pHook->jObj, jHook) ){
/* Same object - this is a no-op. */ /* Same object - this is a no-op. */
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return 0; return 0;
} }
S3JniHook_unref(pHook); S3JniHook_unref(pHook);
@ -3981,7 +3987,7 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
} }
if( rc ) S3JniHook_unref(pHook); if( rc ) S3JniHook_unref(pHook);
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
return rc; return rc;
} }
@ -3998,15 +4004,15 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
){ ){
s3jni_reset_auto_extension(env); s3jni_reset_auto_extension(env);
/* Free up S3JniDb recycling bin. */ /* Free up S3JniDb recycling bin. */
S3JniMutex_S3JniDb_enter; { S3JniDb_mutex_enter; {
while( S3JniGlobal.perDb.aFree ){ while( S3JniGlobal.perDb.aFree ){
S3JniDb * const d = S3JniGlobal.perDb.aFree; S3JniDb * const d = S3JniGlobal.perDb.aFree;
S3JniGlobal.perDb.aFree = d->pNext; S3JniGlobal.perDb.aFree = d->pNext;
S3JniDb_clear(env, d); S3JniDb_clear(env, d);
sqlite3_free(d); sqlite3_free(d);
} }
} S3JniMutex_S3JniDb_leave; } S3JniDb_mutex_leave;
S3JniMutex_Global_enter; { S3JniGlobal_mutex_enter; {
/* Free up S3JniUdf recycling bin. */ /* Free up S3JniUdf recycling bin. */
while( S3JniGlobal.udf.aFree ){ while( S3JniGlobal.udf.aFree ){
S3JniUdf * const u = S3JniGlobal.udf.aFree; S3JniUdf * const u = S3JniGlobal.udf.aFree;
@ -4024,13 +4030,13 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
assert( !u->jExtra ); assert( !u->jExtra );
sqlite3_free( u ); sqlite3_free( u );
} }
} S3JniMutex_Global_leave; } S3JniGlobal_mutex_leave;
/* Free up env cache. */ /* Free up env cache. */
S3JniMutex_Env_enter; { S3JniEnv_mutex_enter; {
while( SJG.envCache.aHead ){ while( SJG.envCache.aHead ){
S3JniEnv_uncache( SJG.envCache.aHead->env ); S3JniEnv_uncache( SJG.envCache.aHead->env );
} }
} S3JniMutex_Env_leave; } S3JniEnv_mutex_leave;
#if 0 #if 0
/* /*
** Is automatically closing any still-open dbs a good idea? We will ** Is automatically closing any still-open dbs a good idea? We will
@ -4038,11 +4044,11 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
** state, at which point we won't have a central list of databases ** state, at which point we won't have a central list of databases
** to close. ** to close.
*/ */
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
while( SJG.perDb.pHead ){ while( SJG.perDb.pHead ){
s3jni_close_db(env, SJG.perDb.pHead->jDb, 2); s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
#endif #endif
/* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */ /* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
return sqlite3_shutdown(); return sqlite3_shutdown();
@ -4128,6 +4134,53 @@ S3JniApi(sqlite3_step(),jint,1step)(
return rc; return rc;
} }
S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
JniArgsEnvClass, jobject jDb, jstring jDbName, jstring jTableName,
jstring jColumnName, jobject jDataType, jobject jCollSeq, jobject jNotNull,
jobject jPrimaryKey, jobject jAutoinc
){
sqlite3 * const db = PtrGet_sqlite3(jDb);
char * zDbName = 0, * zTableName = 0, * zColumnName = 0;
const char * pzCollSeq = 0;
const char * pzDataType = 0;
int pNotNull = 0, pPrimaryKey = 0, pAutoinc = 0;
int rc;
if( !db || !jDbName || !jTableName || !jColumnName ) return SQLITE_MISUSE;
zDbName = s3jni_jstring_to_utf8(jDbName,0);
zTableName = zDbName ? s3jni_jstring_to_utf8(jTableName,0) : 0;
zColumnName = zTableName ? s3jni_jstring_to_utf8(jColumnName,0) : 0;
rc = zColumnName
? sqlite3_table_column_metadata(db, zDbName, zTableName,
zColumnName, &pzDataType, &pzCollSeq,
&pNotNull, &pPrimaryKey, &pAutoinc)
: SQLITE_NOMEM;
if( 0==rc ){
jstring jseq = jCollSeq
? (pzCollSeq ? s3jni_utf8_to_jstring(pzCollSeq, -1) : 0)
: 0;
jstring jdtype = jDataType
? (pzDataType ? s3jni_utf8_to_jstring(pzDataType, -1) : 0)
: 0;
if( (jCollSeq && pzCollSeq && !jseq)
|| (jDataType && pzDataType && !jdtype) ){
rc = SQLITE_NOMEM;
}else{
if( jNotNull ) OutputPointer_set_Bool(env, jNotNull, pNotNull);
if( jPrimaryKey ) OutputPointer_set_Bool(env, jPrimaryKey, pPrimaryKey);
if( jAutoinc ) OutputPointer_set_Bool(env, jAutoinc, pAutoinc);
if( jCollSeq ) OutputPointer_set_String(env, jCollSeq, jseq);
if( jDataType ) OutputPointer_set_String(env, jDataType, jdtype);
}
S3JniUnrefLocal(jseq);
S3JniUnrefLocal(jdtype);
}
sqlite3_free(zDbName);
sqlite3_free(zTableName);
sqlite3_free(zColumnName);
return rc;
}
static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
S3JniDb * const ps = (S3JniDb *)pC; S3JniDb * const ps = (S3JniDb *)pC;
S3JniDeclLocal_env; S3JniDeclLocal_env;
@ -4195,10 +4248,10 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
if( !ps ) return SQLITE_MISUSE; if( !ps ) return SQLITE_MISUSE;
if( !traceMask || !jTracer ){ if( !traceMask || !jTracer ){
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
rc = (jint)sqlite3_trace_v2(ps->pDb, 0, 0, 0); rc = (jint)sqlite3_trace_v2(ps->pDb, 0, 0, 0);
S3JniHook_unref(&ps->hooks.trace); S3JniHook_unref(&ps->hooks.trace);
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
}else{ }else{
jclass const klazz = (*env)->GetObjectClass(env, jTracer); jclass const klazz = (*env)->GetObjectClass(env, jTracer);
S3JniHook hook = S3JniHook_empty; S3JniHook hook = S3JniHook_empty;
@ -4213,7 +4266,7 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
"TracerCallback object."); "TracerCallback object.");
}else{ }else{
hook.jObj = S3JniRefGlobal(jTracer); hook.jObj = S3JniRefGlobal(jTracer);
S3JniMutex_S3JniDb_enter; S3JniDb_mutex_enter;
rc = sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps); rc = sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps);
if( 0==rc ){ if( 0==rc ){
S3JniHook_unref(&ps->hooks.trace); S3JniHook_unref(&ps->hooks.trace);
@ -4221,7 +4274,7 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
}else{ }else{
S3JniHook_unref(&hook); S3JniHook_unref(&hook);
} }
S3JniMutex_S3JniDb_leave; S3JniDb_mutex_leave;
} }
} }
return rc; return rc;
@ -4486,14 +4539,14 @@ static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
jobject pNPH = new_NativePointerHolder_object( jobject pNPH = new_NativePointerHolder_object(
env, &S3JniNphRefs.Fts5ExtensionApi, s3jni_ftsext() env, &S3JniNphRefs.Fts5ExtensionApi, s3jni_ftsext()
); );
S3JniMutex_Env_enter; S3JniEnv_mutex_enter;
if( pNPH ){ if( pNPH ){
if( !SJG.fts5.jFtsExt ){ if( !SJG.fts5.jFtsExt ){
SJG.fts5.jFtsExt = S3JniRefGlobal(pNPH); SJG.fts5.jFtsExt = S3JniRefGlobal(pNPH);
} }
S3JniUnrefLocal(pNPH); S3JniUnrefLocal(pNPH);
} }
S3JniMutex_Env_leave; S3JniEnv_mutex_leave;
} }
return SJG.fts5.jFtsExt; return SJG.fts5.jFtsExt;
} }

View File

@ -1187,6 +1187,14 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1filename
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1handle JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1handle
(JNIEnv *, jclass, jobject); (JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_db_release_memory
* Signature: (Lorg/sqlite/jni/sqlite3;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1release_1memory
(JNIEnv *, jclass, jobject);
/* /*
* Class: org_sqlite_jni_SQLite3Jni * Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_db_status * Method: sqlite3_db_status
@ -1403,6 +1411,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1preupdate_1old
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1progress_1handler JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1progress_1handler
(JNIEnv *, jclass, jobject, jint, jobject); (JNIEnv *, jclass, jobject, jint, jobject);
/*
* Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_release_memory
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1release_1memory
(JNIEnv *, jclass, jint);
/* /*
* Class: org_sqlite_jni_SQLite3Jni * Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_reset * Method: sqlite3_reset
@ -1643,6 +1659,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1strglob
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1strlike JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1strlike
(JNIEnv *, jclass, jbyteArray, jbyteArray, jint); (JNIEnv *, jclass, jbyteArray, jbyteArray, jint);
/*
* Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_table_column_metadata
* Signature: (Lorg/sqlite/jni/sqlite3;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/sqlite/jni/OutputPointer/String;Lorg/sqlite/jni/OutputPointer/String;Lorg/sqlite/jni/OutputPointer/Bool;Lorg/sqlite/jni/OutputPointer/Bool;Lorg/sqlite/jni/OutputPointer/Bool;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1table_1column_1metadata
(JNIEnv *, jclass, jobject, jstring, jstring, jstring, jobject, jobject, jobject, jobject, jobject);
/* /*
* Class: org_sqlite_jni_SQLite3Jni * Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_threadsafe * Method: sqlite3_threadsafe

View File

@ -108,6 +108,26 @@ public final class OutputPointer {
} }
} }
/**
Output pointer for use with native routines which return booleans
via integer output pointers.
*/
public static final class Bool {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public boolean value;
/** Initializes with the value 0. */
public Bool(){this(false);}
/** Initializes with the value v. */
public Bool(boolean v){value = v;}
/** Returns the current value. */
public final boolean get(){return value;}
/** Sets the current value to v. */
public final void set(boolean v){value = v;}
}
/** /**
Output pointer for use with native routines which return integers via Output pointer for use with native routines which return integers via
output pointers. output pointers.

View File

@ -612,6 +612,9 @@ public final class SQLite3Jni {
@Canonical @Canonical
public static native sqlite3 sqlite3_db_handle( @NotNull sqlite3_stmt stmt ); public static native sqlite3 sqlite3_db_handle( @NotNull sqlite3_stmt stmt );
@Canonical
public static native int sqlite3_db_release_memory(sqlite3 db);
@Canonical @Canonical
public static native int sqlite3_db_status( public static native int sqlite3_db_status(
@NotNull sqlite3 db, int op, @NotNull OutputPointer.Int32 pCurrent, @NotNull sqlite3 db, int op, @NotNull OutputPointer.Int32 pCurrent,
@ -972,6 +975,9 @@ public final class SQLite3Jni {
@NotNull sqlite3 db, int n, @Nullable ProgressHandlerCallback h @NotNull sqlite3 db, int n, @Nullable ProgressHandlerCallback h
); );
@Canonical
public static native int sqlite3_release_memory(int n);
@Canonical @Canonical
public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt); public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt);
@ -1304,7 +1310,6 @@ public final class SQLite3Jni {
@Canonical @Canonical
public static native String sqlite3_sql(@NotNull sqlite3_stmt stmt); public static native String sqlite3_sql(@NotNull sqlite3_stmt stmt);
@Canonical @Canonical
public static native int sqlite3_status( public static native int sqlite3_status(
int op, @NotNull OutputPointer.Int32 pCurrent, int op, @NotNull OutputPointer.Int32 pCurrent,
@ -1357,6 +1362,17 @@ public final class SQLite3Jni {
); );
} }
@Canonical
public static native int sqlite3_table_column_metadata(
@NotNull sqlite3 db, @NotNull String zDbName,
@NotNull String zTableName, @NotNull String zColumnName,
@Nullable OutputPointer.String pzDataType,
@Nullable OutputPointer.String pzCollSeq,
@Nullable OutputPointer.Bool pNotNull,
@Nullable OutputPointer.Bool pPrimaryKey,
@Nullable OutputPointer.Bool pAutoinc
);
@Canonical @Canonical
public static native int sqlite3_threadsafe(); public static native int sqlite3_threadsafe();

View File

@ -731,6 +731,7 @@ public class Tester1 implements Runnable {
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
affirm( 1 == n ); affirm( 1 == n );
affirm( 0==sqlite3_db_release_memory(db) );
sqlite3_close_v2(db); sqlite3_close_v2(db);
} }
@ -1359,6 +1360,30 @@ public class Tester1 implements Runnable {
affirm( 8 == val.value ); affirm( 8 == val.value );
} }
private void testColumnMetadata(){
sqlite3 db = createNewDb();
execSql(db, new String[] {
"CREATE TABLE t(a duck primary key not null collate noCase); ",
"INSERT INTO t(a) VALUES(1),(2),(3);"
});
OutputPointer.Bool bNotNull = new OutputPointer.Bool();
OutputPointer.Bool bPrimaryKey = new OutputPointer.Bool();
OutputPointer.Bool bAutoinc = new OutputPointer.Bool();
OutputPointer.String zCollSeq = new OutputPointer.String();
OutputPointer.String zDataType = new OutputPointer.String();
int rc = sqlite3_table_column_metadata(
db, "main", "t", "a", zDataType, zCollSeq,
bNotNull, bPrimaryKey, bAutoinc);
affirm( 0==rc );
affirm( bPrimaryKey.value );
affirm( !bAutoinc.value );
affirm( bNotNull.value );
affirm( "noCase".equals(zCollSeq.value) );
affirm( "duck".equals(zDataType.value) );
sqlite3_close_v2(db);
}
@ManualTest /* we really only want to run this test manually. */ @ManualTest /* we really only want to run this test manually. */
private void testSleep(){ private void testSleep(){
out("Sleeping briefly... "); out("Sleeping briefly... ");
@ -1618,6 +1643,7 @@ public class Tester1 implements Runnable {
if( doSomethingForDev ){ if( doSomethingForDev ){
sqlite3_jni_internal_details(); sqlite3_jni_internal_details();
} }
affirm( 0==sqlite3_release_memory(1) );
sqlite3_shutdown(); sqlite3_shutdown();
int nMethods = 0; int nMethods = 0;
int nNatives = 0; int nNatives = 0;

View File

@ -1,5 +1,5 @@
C Use\smutexes\sto\smake\ssqlite3_set_clientdata()\sand\ssqlite3_get_clientdata()\nthreadsafe. C Export\ssqlite3_(db_)free_memory()\sand\ssqlite3_table_column_metadata()\sto\sJNI.\sFurther\sinternals\srenaming\sfor\sconsistency\sand\slegibility.
D 2023-08-30T18:51:26.770 D 2023-08-31T14:57:01.532
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
@ -237,8 +237,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551 F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9 F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c aaec2851258a7d9c9907d8e864a17e055676ec0adb64f335d979fa19674a0cab F ext/jni/src/c/sqlite3-jni.c 2364ccb4445c5f45a4d4b80d28455fe0c547f5529e5bd8610b4ba3811c82cc78
F ext/jni/src/c/sqlite3-jni.h 12e1a5ef5ee1795dc22577c285b4518dfd8aa4af45757f6cb81a555d967bf201 F ext/jni/src/c/sqlite3-jni.h d9ea1662cefe7d8a2737cdbc55799a7e407cbc2239769f486d8eb33b68b9f133
F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436 F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4 F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java d00a2409ab76cae168927e2ca6a7ffbd0621a42547cce88768b4eeebc13827e0 F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java d00a2409ab76cae168927e2ca6a7ffbd0621a42547cce88768b4eeebc13827e0
@ -255,16 +255,16 @@ F ext/jni/src/org/sqlite/jni/Fts5Function.java 65cde7151e441fee012250a5e03277de7
F ext/jni/src/org/sqlite/jni/Fts5PhraseIter.java 6642beda341c0b1b46af4e2d7f6f9ab03a7aede43277b2c92859176d6bce3be9 F ext/jni/src/org/sqlite/jni/Fts5PhraseIter.java 6642beda341c0b1b46af4e2d7f6f9ab03a7aede43277b2c92859176d6bce3be9
F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b55809c26e2b797fb321dfcdbc1298c060 F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b55809c26e2b797fb321dfcdbc1298c060
F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 564087036449a16df148dcf0a067408bd251170bf23286c655f46b5f973e8b2d F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 564087036449a16df148dcf0a067408bd251170bf23286c655f46b5f973e8b2d
F ext/jni/src/org/sqlite/jni/OutputPointer.java 4ae06135decef35eb04498daa2868939d91a294e948747c580ef9ce31563a6b3 F ext/jni/src/org/sqlite/jni/OutputPointer.java 1f2319976fff206f5056eafc8a4f48d43abe09d5d1b5287ba9145a95d847cbb7
F ext/jni/src/org/sqlite/jni/PreupdateHookCallback.java 500c968b3893edbddf67e8eb773852c3a8ae58097a77bd22320ada6b1af06db1 F ext/jni/src/org/sqlite/jni/PreupdateHookCallback.java 500c968b3893edbddf67e8eb773852c3a8ae58097a77bd22320ada6b1af06db1
F ext/jni/src/org/sqlite/jni/ProgressHandlerCallback.java 0da841810319f5a9dc372d0f2348930d54fac1a4b53e4298884f44c720d67830 F ext/jni/src/org/sqlite/jni/ProgressHandlerCallback.java 0da841810319f5a9dc372d0f2348930d54fac1a4b53e4298884f44c720d67830
F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86 F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java 16042be9d072a26dbb2f1b1b63e7639989b747bb80d2bd667ba4f7555f56a825 F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java 16042be9d072a26dbb2f1b1b63e7639989b747bb80d2bd667ba4f7555f56a825
F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b29971d715a821a4fad3c899113ee8c F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b29971d715a821a4fad3c899113ee8c
F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java c2748ab52856075b053a55b317988d95dc7fb4d3d42520f8c33573effe1cd185 F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java c2748ab52856075b053a55b317988d95dc7fb4d3d42520f8c33573effe1cd185
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 440d64e8c4cff53bd3c0cc676381212489198302d7f1aaa535712c2d7163cc69 F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 548ab462e161118b50a614a8bbc2fc2abd507f9b0632267fc78bdd8926ad0807
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
F ext/jni/src/org/sqlite/jni/Tester1.java 21d78aa59bfc5ce5ff242d4bb6f6d2255d162fba8be5859ab87c9201d61433f0 F ext/jni/src/org/sqlite/jni/Tester1.java 05750f0ea53057de146fce8d06b7314009732de06f1e4843c87aa28ba940d6f7
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
F ext/jni/src/org/sqlite/jni/TraceV2Callback.java 641926b05a772c2c05c842a81aa839053ba4a13b78ef04b402f5705d060c6246 F ext/jni/src/org/sqlite/jni/TraceV2Callback.java 641926b05a772c2c05c842a81aa839053ba4a13b78ef04b402f5705d060c6246
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java be2bc96ff4f56b3c1fd18ae7dba9b207b25b6c123b8a5fd2f7aaf3cc208d8b7d F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java be2bc96ff4f56b3c1fd18ae7dba9b207b25b6c123b8a5fd2f7aaf3cc208d8b7d
@ -2115,8 +2115,11 @@ 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 e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e P 443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
R 3f04e2f3da46f99baea85816871f54e6 R d454ebcc01c88272e67e43cac0f5ee2a
U drh T *branch * jni-client-data
Z 4a72dec53887e83eac398e1a9fd59cf2 T *sym-jni-client-data *
T -sym-db-client-data * Cancelled\sby\sbranch.
U stephan
Z c9e44a2d4b476765181f0fdc6d845bb0
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29 7c86aa3400ed591d38c1828f366f4b5de97954c2b301919d3f06d9c2d3d7d1f2