mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
More code legibility and style improvements in the JNI pieces. Start work on a javadoc build.
FossilOrigin-Name: 62b404d62fd62f4d220838b59c9f38a71afa2d4a8c3af0a5c9495fa7020972cf
This commit is contained in:
@@ -6,9 +6,10 @@ JAVA_HOME ?= $(HOME)/jdk/current
|
||||
# e.g. /usr/lib/jvm/default-javajava-19-openjdk-amd64
|
||||
JDK_HOME ?= $(JAVA_HOME)
|
||||
# ^^^ JDK_HOME is not as widely used as JAVA_HOME
|
||||
bin.javac := $(JDK_HOME)/bin/javac
|
||||
bin.java := $(JDK_HOME)/bin/java
|
||||
bin.jar := $(JDK_HOME)/bin/jar
|
||||
bin.jar := $(JDK_HOME)/bin/jar
|
||||
bin.java := $(JDK_HOME)/bin/java
|
||||
bin.javac := $(JDK_HOME)/bin/javac
|
||||
bin.javadoc := $(JDK_HOME)/bin/javadoc
|
||||
ifeq (,$(wildcard $(JDK_HOME)))
|
||||
$(error set JDK_HOME to the top-most dir of your JDK installation.)
|
||||
endif
|
||||
@@ -17,18 +18,18 @@ $(MAKEFILE):
|
||||
|
||||
package.jar := sqlite3-jni.jar
|
||||
|
||||
dir.top := ../..
|
||||
dir.tool := ../../tool
|
||||
dir.jni := $(patsubst %/,%,$(dir $(MAKEFILE)))
|
||||
|
||||
dir.top := ../..
|
||||
dir.tool := ../../tool
|
||||
dir.jni := $(patsubst %/,%,$(dir $(MAKEFILE)))
|
||||
dir.src := $(dir.jni)/src
|
||||
dir.src.c := $(dir.src)/c
|
||||
dir.bld := $(dir.jni)/bld
|
||||
dir.bld.c := $(dir.bld)
|
||||
dir.src.jni := $(dir.src)/org/sqlite/jni
|
||||
dir.src.jni.tester := $(dir.src.jni)/tester
|
||||
mkdir := mkdir -p
|
||||
$(dir.bld.c):
|
||||
mkdir -p $@
|
||||
$(mkdir) $@
|
||||
|
||||
classpath := $(dir.src)
|
||||
CLEAN_FILES := $(package.jar)
|
||||
@@ -285,6 +286,12 @@ $(package.jar): $(CLASS_FILES) $(MAKEFILE) $(package.jar.in)
|
||||
|
||||
jar: $(package.jar)
|
||||
|
||||
dir.doc := $(dir.jni)/doc
|
||||
doc: $(JAVA_FILES.main)
|
||||
$(bin.javadoc) -cp $(classpath) -d $(dir.doc) org.sqlite.jni
|
||||
|
||||
########################################################################
|
||||
# Clean up...
|
||||
CLEAN_FILES += $(dir.bld.c)/* \
|
||||
$(dir.src.jni)/*.class \
|
||||
$(dir.src.jni.tester)/*.class \
|
||||
|
||||
@@ -297,7 +297,7 @@ enum {
|
||||
** index field of those entries are the keys for this particular
|
||||
** cache.
|
||||
*/
|
||||
NphCache_SIZE = sizeof(S3NphRefs) / sizeof(S3NphRef)
|
||||
S3Jni_NphCache_size = sizeof(S3NphRefs) / sizeof(S3NphRef)
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -318,12 +318,16 @@ struct S3JniNphClass {
|
||||
** by the sqlite3_context binding. */;
|
||||
};
|
||||
|
||||
/** State for various hook callbacks. */
|
||||
/*
|
||||
** State for binding C callbacks to Java methods.
|
||||
*/
|
||||
typedef struct S3JniHook S3JniHook;
|
||||
struct S3JniHook{
|
||||
jobject jObj /* global ref to Java instance */;
|
||||
jmethodID midCallback /* callback method. Signature depends on
|
||||
** jObj's type */;
|
||||
/* We lookup the jObj.xDestroy() method as-needed for contexts which
|
||||
** have custom finalizers. */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -433,10 +437,11 @@ struct S3JniGlobalType {
|
||||
** JNIEnv when necessary.
|
||||
*/
|
||||
JavaVM * jvm;
|
||||
/* Cache of Java refs/IDs for NativePointerHolder subclasses.
|
||||
/*
|
||||
** Cache of Java refs/IDs for NativePointerHolder subclasses.
|
||||
** Initialized on demand.
|
||||
*/
|
||||
S3JniNphClass nph[NphCache_SIZE];
|
||||
S3JniNphClass nph[S3Jni_NphCache_size];
|
||||
/*
|
||||
** Cache of per-thread state.
|
||||
*/
|
||||
@@ -542,47 +547,47 @@ static void s3jni_incr( volatile unsigned int * const p ){
|
||||
#endif
|
||||
|
||||
/* Helpers for working with specific mutexes. */
|
||||
#define MUTEX_ENV_ASSERT_LOCKED \
|
||||
#define S3JniMutex_Env_assertLocked \
|
||||
assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
||||
#define MUTEX_ENV_ASSERT_LOCKER \
|
||||
#define S3JniMutex_Env_assertLocker \
|
||||
assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
||||
#define MUTEX_ENV_ASSERT_NOTLOCKER \
|
||||
#define S3JniMutex_Env_assertNotLocker \
|
||||
assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
||||
#define MUTEX_ENV_ENTER \
|
||||
MUTEX_ENV_ASSERT_NOTLOCKER; \
|
||||
#define S3JniMutex_Env_enter \
|
||||
S3JniMutex_Env_assertNotLocker; \
|
||||
/*MARKER(("Entering ENV mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_enter( SJG.envCache.mutex ); \
|
||||
++SJG.metrics.nMutexEnv; \
|
||||
SJG.envCache.locker = env
|
||||
#define MUTEX_ENV_LEAVE \
|
||||
#define S3JniMutex_Env_leave \
|
||||
/*MARKER(("Leaving ENV mutex @%p %s.\n", env));*/ \
|
||||
MUTEX_ENV_ASSERT_LOCKER; \
|
||||
S3JniMutex_Env_assertLocker; \
|
||||
SJG.envCache.locker = 0; \
|
||||
sqlite3_mutex_leave( SJG.envCache.mutex )
|
||||
#define MUTEX_EXT_ENTER \
|
||||
#define S3JniMutex_Ext_enter \
|
||||
/*MARKER(("Entering autoExt mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_enter( SJG.autoExt.mutex ); \
|
||||
++SJG.metrics.nMutexAutoExt
|
||||
#define MUTEX_EXT_LEAVE \
|
||||
#define S3JniMutex_Ext_leave \
|
||||
/*MARKER(("Leaving autoExt mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_leave( SJG.autoExt.mutex )
|
||||
#define MUTEX_NPH_ENTER \
|
||||
MUTEX_ENV_ASSERT_NOTLOCKER; \
|
||||
#define S3JniMutex_Nph_enter \
|
||||
S3JniMutex_Env_assertNotLocker; \
|
||||
/*MARKER(("Entering NPH mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_enter( SJG.envCache.mutex ); \
|
||||
++SJG.metrics.nMutexEnv2; \
|
||||
SJG.envCache.locker = env
|
||||
#define MUTEX_NPH_LEAVE \
|
||||
#define S3JniMutex_Nph_leave \
|
||||
/*MARKER(("Leaving NPH mutex @%p %s.\n", env));*/ \
|
||||
MUTEX_ENV_ASSERT_LOCKER; \
|
||||
S3JniMutex_Env_assertLocker; \
|
||||
SJG.envCache.locker = 0; \
|
||||
sqlite3_mutex_leave( SJG.envCache.mutex )
|
||||
#define MUTEX_PDB_ENTER \
|
||||
#define S3JniMutex_Pdb_enter \
|
||||
/*MARKER(("Entering PerDb mutex@%p %s.\n", env));*/ \
|
||||
sqlite3_mutex_enter( SJG.perDb.mutex ); \
|
||||
++SJG.metrics.nMutexPerDb; \
|
||||
SJG.perDb.locker = env;
|
||||
#define MUTEX_PDB_LEAVE \
|
||||
#define S3JniMutex_Pdb_leave \
|
||||
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env));*/ \
|
||||
SJG.perDb.locker = 0; \
|
||||
sqlite3_mutex_leave( SJG.perDb.mutex )
|
||||
@@ -612,12 +617,12 @@ static void * s3jni_malloc(JNIEnv * const env, size_t n){
|
||||
*/
|
||||
static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
|
||||
struct S3JniEnv * row;
|
||||
MUTEX_ENV_ENTER;
|
||||
S3JniMutex_Env_enter;
|
||||
row = SJG.envCache.aHead;
|
||||
for( ; row; row = row->pNext ){
|
||||
if( row->env == env ){
|
||||
s3jni_incr( &SJG.metrics.envCacheHits );
|
||||
MUTEX_ENV_LEAVE;
|
||||
S3JniMutex_Env_leave;
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -637,7 +642,7 @@ static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
|
||||
SJG.envCache.aHead = row;
|
||||
row->env = env;
|
||||
|
||||
MUTEX_ENV_LEAVE;
|
||||
S3JniMutex_Env_leave;
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -897,7 +902,7 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDest
|
||||
*/
|
||||
static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){
|
||||
if(s){
|
||||
MUTEX_PDB_ENTER;
|
||||
S3JniMutex_Pdb_enter;
|
||||
assert(s->pPrev != s);
|
||||
assert(s->pNext != s);
|
||||
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
|
||||
@@ -927,7 +932,7 @@ static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){
|
||||
s->pNext = SJG.perDb.aFree;
|
||||
if(s->pNext) s->pNext->pPrev = s;
|
||||
SJG.perDb.aFree = s;
|
||||
MUTEX_PDB_LEAVE;
|
||||
S3JniMutex_Pdb_leave;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,7 +943,7 @@ static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){
|
||||
*/
|
||||
static int S3JniGlobal_env_uncache(JNIEnv * const env){
|
||||
struct S3JniEnv * row;
|
||||
MUTEX_ENV_ASSERT_LOCKED;
|
||||
S3JniMutex_Env_assertLocked;
|
||||
row = SJG.envCache.aHead;
|
||||
for( ; row; row = row->pNext ){
|
||||
if( row->env == env ){
|
||||
@@ -967,7 +972,7 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
|
||||
**
|
||||
** It is up to the caller to populate the other members of the
|
||||
** returned object if needed, taking care to lock the population with
|
||||
** MUTEX_NPH_ENTER/LEAVE.
|
||||
** S3JniMutex_Nph_enter/LEAVE.
|
||||
**
|
||||
** This simple cache catches >99% of searches in the current
|
||||
** (2023-07-31) tests.
|
||||
@@ -989,15 +994,17 @@ static S3JniNphClass * S3JniGlobal_nph_cache(JNIEnv * const env, S3NphRef const*
|
||||
cached as well.
|
||||
*/
|
||||
S3JniNphClass * const pNC = &SJG.nph[pRef->index];
|
||||
assert( (void*)pRef>=(void*)&S3NphRefs && (void*)pRef<(void*)(&S3NphRefs + 1)
|
||||
&& "pRef is out of range." );
|
||||
if( !pNC->pRef ){
|
||||
MUTEX_NPH_ENTER;
|
||||
S3JniMutex_Nph_enter;
|
||||
if( !pNC->pRef ){
|
||||
pNC->pRef = pRef;
|
||||
pNC->klazz = (*env)->FindClass(env, pRef->zName);
|
||||
EXCEPTION_IS_FATAL("FindClass() unexpectedly threw");
|
||||
pNC->klazz = REF_G(pNC->klazz);
|
||||
}
|
||||
MUTEX_NPH_LEAVE;
|
||||
S3JniMutex_Nph_leave;
|
||||
}
|
||||
return pNC;
|
||||
}
|
||||
@@ -1009,12 +1016,12 @@ static S3JniNphClass * S3JniGlobal_nph_cache(JNIEnv * const env, S3NphRef const*
|
||||
static jfieldID NativePointerHolder_getField(JNIEnv * const env, S3NphRef const* pRef){
|
||||
S3JniNphClass * const pNC = S3JniGlobal_nph_cache(env, pRef);
|
||||
if( !pNC->fidValue ){
|
||||
MUTEX_NPH_ENTER;
|
||||
S3JniMutex_Nph_enter;
|
||||
if( !pNC->fidValue ){
|
||||
pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz, "nativePointer", "J");
|
||||
EXCEPTION_IS_FATAL("Code maintenance required: missing nativePointer field.");
|
||||
}
|
||||
MUTEX_NPH_LEAVE;
|
||||
S3JniMutex_Nph_leave;
|
||||
}
|
||||
return pNC->fidValue;
|
||||
}
|
||||
@@ -1057,7 +1064,7 @@ static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, S3NphRef const
|
||||
static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
|
||||
jobject jDb){
|
||||
S3JniDb * rv;
|
||||
MUTEX_PDB_ENTER;
|
||||
S3JniMutex_Pdb_enter;
|
||||
if( SJG.perDb.aFree ){
|
||||
rv = SJG.perDb.aFree;
|
||||
SJG.perDb.aFree = rv->pNext;
|
||||
@@ -1088,7 +1095,7 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
|
||||
rv->jDb = REF_G(jDb);
|
||||
rv->pDb = pDb;
|
||||
}
|
||||
MUTEX_PDB_LEAVE;
|
||||
S3JniMutex_Pdb_leave;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1106,7 +1113,7 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
|
||||
static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
|
||||
S3JniDb * s = 0;
|
||||
if( jDb || pDb ){
|
||||
MUTEX_PDB_ENTER;
|
||||
S3JniMutex_Pdb_enter;
|
||||
s = SJG.perDb.aUsed;
|
||||
if( !pDb ){
|
||||
assert( jDb );
|
||||
@@ -1117,7 +1124,7 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
|
||||
break;
|
||||
}
|
||||
}
|
||||
MUTEX_PDB_LEAVE;
|
||||
S3JniMutex_Pdb_leave;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -1183,12 +1190,12 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
|
||||
S3JniNphClass * const pNC =
|
||||
S3JniGlobal_nph_cache(env, &S3NphRefs.sqlite3_context);
|
||||
if( !pNC->fidAggCtx ){
|
||||
MUTEX_NPH_ENTER;
|
||||
S3JniMutex_Nph_enter;
|
||||
if( !pNC->fidAggCtx ){
|
||||
pNC->fidAggCtx = (*env)->GetFieldID(env, pNC->klazz, "aggregateContext", "J");
|
||||
EXCEPTION_IS_FATAL("Cannot get sqlite3_contex.aggregateContext member.");
|
||||
}
|
||||
MUTEX_NPH_LEAVE;
|
||||
S3JniMutex_Nph_leave;
|
||||
}
|
||||
pAgg = sqlite3_aggregate_context(pCx, isFinal ? 0 : sizeof(void*));
|
||||
if( pAgg || isFinal ){
|
||||
@@ -1218,12 +1225,12 @@ static jfieldID setupOutputPointer(JNIEnv * const env, S3NphRef const * pRef,
|
||||
jobject const jOut){
|
||||
S3JniNphClass * const pNC = S3JniGlobal_nph_cache(env, pRef);
|
||||
if( !pNC->fidValue ){
|
||||
MUTEX_NPH_ENTER;
|
||||
S3JniMutex_Nph_enter;
|
||||
if( !pNC->fidValue ){
|
||||
pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz, "value", zTypeSig);
|
||||
EXCEPTION_IS_FATAL("setupOutputPointer() could not find OutputPointer.*.value");
|
||||
}
|
||||
MUTEX_NPH_LEAVE;
|
||||
S3JniMutex_Nph_leave;
|
||||
}
|
||||
return pNC->fidValue;
|
||||
}
|
||||
@@ -1430,12 +1437,12 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const
|
||||
jobject rv = 0;
|
||||
S3JniNphClass * const pNC = S3JniGlobal_nph_cache(env, pRef);
|
||||
if( !pNC->midCtor ){
|
||||
MUTEX_NPH_ENTER;
|
||||
S3JniMutex_Nph_enter;
|
||||
if( !pNC->midCtor ){
|
||||
pNC->midCtor = (*env)->GetMethodID(env, pNC->klazz, "<init>", "()V");
|
||||
EXCEPTION_IS_FATAL("Cannot find constructor for class.");
|
||||
}
|
||||
MUTEX_NPH_LEAVE;
|
||||
S3JniMutex_Nph_leave;
|
||||
}
|
||||
rv = (*env)->NewObject(env, pNC->klazz, pNC->midCtor);
|
||||
EXCEPTION_IS_FATAL("No-arg constructor threw.");
|
||||
@@ -1855,14 +1862,14 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
|
||||
** local reference to it, to avoid a race condition with another
|
||||
** thread manipulating the list during the call and invaliding
|
||||
** what ax points to. */;
|
||||
MUTEX_EXT_ENTER;
|
||||
S3JniMutex_Ext_enter;
|
||||
if( i >= SJG.autoExt.nExt ){
|
||||
go = 0;
|
||||
}else{
|
||||
ax.jObj = REF_L(SJG.autoExt.pExt[i].jObj);
|
||||
ax.midFunc = SJG.autoExt.pExt[i].midFunc;
|
||||
}
|
||||
MUTEX_EXT_LEAVE;
|
||||
S3JniMutex_Ext_leave;
|
||||
if( ax.jObj ){
|
||||
rc = (*env)->CallIntMethod(env, ax.jObj, ax.midFunc, ps->jDb);
|
||||
UNREF_L(ax.jObj);
|
||||
@@ -1890,12 +1897,12 @@ S3JniApi(sqlite3_auto_extension(),jint,1auto_1extension)(
|
||||
int rc = 0;
|
||||
|
||||
if( !jAutoExt ) return SQLITE_MISUSE;
|
||||
MUTEX_EXT_ENTER;
|
||||
S3JniMutex_Ext_enter;
|
||||
for( i = 0; i < SJG.autoExt.nExt; ++i ){
|
||||
/* Look for match or first empty slot. */
|
||||
ax = &SJG.autoExt.pExt[i];
|
||||
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
||||
MUTEX_EXT_LEAVE;
|
||||
S3JniMutex_Ext_leave;
|
||||
return 0 /* this as a no-op. */;
|
||||
}
|
||||
}
|
||||
@@ -1931,7 +1938,7 @@ S3JniApi(sqlite3_auto_extension(),jint,1auto_1extension)(
|
||||
++SJG.autoExt.nExt;
|
||||
}
|
||||
}
|
||||
MUTEX_EXT_LEAVE;
|
||||
S3JniMutex_Ext_leave;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2082,7 +2089,7 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
|
||||
S3JniAutoExtension * ax;
|
||||
jboolean rc = JNI_FALSE;
|
||||
int i;
|
||||
MUTEX_EXT_ENTER;
|
||||
S3JniMutex_Ext_enter;
|
||||
/* This algo mirrors the one in the core. */
|
||||
for( i = SJG.autoExt.nExt-1; i >= 0; --i ){
|
||||
ax = &SJG.autoExt.pExt[i];
|
||||
@@ -2098,7 +2105,7 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
|
||||
break;
|
||||
}
|
||||
}
|
||||
MUTEX_EXT_LEAVE;
|
||||
S3JniMutex_Ext_leave;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3204,12 +3211,12 @@ S3JniApi(sqlite3_reset(),jint,1reset)(
|
||||
/* Clears all entries from S3JniGlobal.autoExt. */
|
||||
static void s3jni_reset_auto_extension(JNIEnv *env){
|
||||
int i;
|
||||
MUTEX_EXT_ENTER;
|
||||
S3JniMutex_Ext_enter;
|
||||
for( i = 0; i < SJG.autoExt.nExt; ++i ){
|
||||
S3JniAutoExtension_clear( env, &SJG.autoExt.pExt[i] );
|
||||
}
|
||||
SJG.autoExt.nExt = 0;
|
||||
MUTEX_EXT_LEAVE;
|
||||
S3JniMutex_Ext_leave;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_reset_auto_extension(),void,1reset_1auto_1extension)(
|
||||
@@ -3571,11 +3578,11 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
|
||||
JniArgsEnvClass
|
||||
){
|
||||
s3jni_reset_auto_extension(env);
|
||||
MUTEX_ENV_ENTER;
|
||||
S3JniMutex_Env_enter;
|
||||
while( SJG.envCache.aHead ){
|
||||
S3JniGlobal_env_uncache( SJG.envCache.aHead->env );
|
||||
}
|
||||
MUTEX_ENV_LEAVE;
|
||||
S3JniMutex_Env_leave;
|
||||
/* Do not clear S3JniGlobal.jvm: it's legal to call
|
||||
sqlite3_initialize() again to restart the lib. */
|
||||
return sqlite3_shutdown();
|
||||
@@ -3812,7 +3819,7 @@ JniDecl(void,1do_1something_1for_1developer)(JniArgsEnvClass){
|
||||
SO(S3JniDb);
|
||||
SO(S3NphRefs);
|
||||
printf("\t(^^^ %u NativePointerHolder subclasses)\n",
|
||||
(unsigned)NphCache_SIZE);
|
||||
(unsigned)S3Jni_NphCache_size);
|
||||
SO(S3JniGlobal);
|
||||
SO(S3JniAutoExtension);
|
||||
SO(S3JniUdf);
|
||||
@@ -3945,14 +3952,14 @@ static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
|
||||
jobject pNPH = new_NativePointerHolder_object(
|
||||
env, &S3NphRefs.Fts5ExtensionApi, s3jni_ftsext()
|
||||
);
|
||||
MUTEX_ENV_ENTER;
|
||||
S3JniMutex_Env_enter;
|
||||
if( pNPH ){
|
||||
if( !SJG.fts5.jFtsExt ){
|
||||
SJG.fts5.jFtsExt = REF_G(pNPH);
|
||||
}
|
||||
UNREF_L(pNPH);
|
||||
}
|
||||
MUTEX_ENV_LEAVE;
|
||||
S3JniMutex_Env_leave;
|
||||
}
|
||||
return SJG.fts5.jFtsExt;
|
||||
}
|
||||
@@ -4655,9 +4662,9 @@ Java_org_sqlite_jni_tester_SQLTester_installCustomExtensions(JniArgsEnvClass){
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JniArgsEnvClass){
|
||||
int rc;
|
||||
MUTEX_ENV_ENTER;
|
||||
S3JniMutex_Env_enter;
|
||||
rc = S3JniGlobal_env_uncache(env);
|
||||
MUTEX_ENV_LEAVE;
|
||||
S3JniMutex_Env_leave;
|
||||
return rc ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1789,10 +1789,10 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1subtype
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_do_something_for_developer
|
||||
* Method: sqlite3_jni_internal_details
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1do_1something_1for_1developer
|
||||
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1jni_1internal_1details
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.sqlite.jni;
|
||||
access to the callback functions needed in order to implement SQL
|
||||
functions in Java.
|
||||
|
||||
<p>
|
||||
|
||||
This class is not used by itself, but is a marker base class. The
|
||||
three UDF types are modelled by the inner classes Scalar,
|
||||
Aggregate<T>, and Window<T>. Most simply, clients may subclass
|
||||
@@ -36,19 +38,19 @@ public abstract class SQLFunction {
|
||||
managing their accumulator state across calls to the UDF's
|
||||
callbacks.
|
||||
|
||||
If a given aggregate or window function is called multiple times
|
||||
<p>If a given aggregate or window function is called multiple times
|
||||
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
|
||||
then the clients need some way of knowing which call is which so
|
||||
that they can map their state between their various UDF callbacks
|
||||
and reset it via xFinal(). This class takes care of such
|
||||
mappings.
|
||||
|
||||
This class works by mapping
|
||||
<p>This class works by mapping
|
||||
sqlite3_context.getAggregateContext() to a single piece of
|
||||
state, of a client-defined type (the T part of this class), which
|
||||
persists across a "matching set" of the UDF's callbacks.
|
||||
|
||||
This class is a helper providing commonly-needed functionality -
|
||||
<p>This class is a helper providing commonly-needed functionality -
|
||||
it is not required for use with aggregate or window functions.
|
||||
Client UDFs are free to perform such mappings using custom
|
||||
approaches. The provided Aggregate<T> and Window<T> classes
|
||||
@@ -69,7 +71,7 @@ public abstract class SQLFunction {
|
||||
without requiring that the client update the underlying map's
|
||||
entry.
|
||||
|
||||
T must be of a type which can be legally stored as a value in
|
||||
<p>T must be of a type which can be legally stored as a value in
|
||||
java.util.HashMap<KeyType,T>.
|
||||
*/
|
||||
public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
|
||||
@@ -95,7 +97,9 @@ public abstract class SQLFunction {
|
||||
}
|
||||
}
|
||||
|
||||
//! Subclass for creating scalar functions.
|
||||
/**
|
||||
Subclass for creating scalar functions.
|
||||
*/
|
||||
public static abstract class Scalar extends SQLFunction {
|
||||
|
||||
/**
|
||||
@@ -151,7 +155,7 @@ public abstract class SQLFunction {
|
||||
argument, the context is set to the given initial value. On all other
|
||||
calls, the 2nd argument is ignored.
|
||||
|
||||
@see PerContextState<T>#takeAggregateState()
|
||||
@see SQLFunction.PerContextState#getAggregateState()
|
||||
*/
|
||||
protected final ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
|
||||
return map.getAggregateState(cx, initialValue);
|
||||
@@ -161,7 +165,7 @@ public abstract class SQLFunction {
|
||||
To be called from the implementation's xFinal() method to fetch
|
||||
the final state of the UDF and remove its mapping.
|
||||
|
||||
@see PerContextState<T>#takeAggregateState()
|
||||
see SQLFunction.PerContextState#takeAggregateState()
|
||||
*/
|
||||
protected final T takeAggregateState(sqlite3_context cx){
|
||||
return map.takeAggregateState(cx);
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.lang.annotation.ElementType;
|
||||
|
||||
/**
|
||||
This annotation is for flagging parameters which may not legally be
|
||||
null. Note that the C-style API does _not_ throw any
|
||||
null. Note that the C-style API does not throw any
|
||||
NullPointerExceptions on its own because it has a no-throw policy
|
||||
in order to retain its C-style semantics.
|
||||
|
||||
@@ -50,62 +50,64 @@ import java.lang.annotation.ElementType;
|
||||
This class contains the entire sqlite3 JNI API binding. For
|
||||
client-side use, a static import is recommended:
|
||||
|
||||
```
|
||||
{@code
|
||||
import static org.sqlite.jni.SQLite3Jni.*;
|
||||
```
|
||||
}
|
||||
|
||||
The C-side part can be found in sqlite3-jni.c.
|
||||
|
||||
|
||||
Only functions which materially differ from their C counterparts
|
||||
<p>Only functions which materially differ from their C counterparts
|
||||
are documented here. The C documetation is otherwise applicable
|
||||
here:
|
||||
|
||||
https://sqlite.org/c3ref/intro.html
|
||||
<p>{link https://sqlite.org/c3ref/intro.html}
|
||||
|
||||
A handful of Java-specific APIs have been added.
|
||||
<p>A handful of Java-specific APIs have been added.
|
||||
|
||||
|
||||
******************************************************************
|
||||
*** Warning regarding Java's Modified UTF-8 vs standard UTF-8: ***
|
||||
******************************************************************
|
||||
<p>Notes regarding Java's Modified UTF-8 vs standard UTF-8:
|
||||
|
||||
SQLite internally uses UTF-8 encoding, whereas Java natively uses
|
||||
<p>SQLite internally uses UTF-8 encoding, whereas Java natively uses
|
||||
UTF-16. Java JNI has routines for converting to and from UTF-8,
|
||||
_but_ JNI uses what its docs call modified UTF-8 (see links below)
|
||||
but JNI uses what its docs call modified UTF-8 (see links below)
|
||||
Care must be taken when converting Java strings to or from standard
|
||||
UTF-8 to ensure that the proper conversion is performed. In short,
|
||||
Java's `String.getBytes(StandardCharsets.UTF_8)` performs the proper
|
||||
conversion in Java, and there are no JNI C APIs for that conversion
|
||||
(JNI's `NewStringUTF()` requires its input to be in MUTF-8).
|
||||
|
||||
The known consequences and limitations this discrepancy places on
|
||||
<p>The known consequences and limitations this discrepancy places on
|
||||
the SQLite3 JNI binding include:
|
||||
|
||||
- Any functions which return state from a database take extra care
|
||||
to perform proper conversion, at the cost of efficiency.
|
||||
<ul>
|
||||
|
||||
- C functions which take C-style strings without a length argument
|
||||
require special care when taking input from Java. In particular,
|
||||
Java strings converted to byte arrays for encoding purposes are
|
||||
not NUL-terminated, and conversion to a Java byte array must be
|
||||
careful to add one. Functions which take a length do not require
|
||||
this so long as the length is provided. Search the SQLite3Jni
|
||||
class for "\0" for many examples.
|
||||
<li>Any functions which return state from a database take extra care
|
||||
to perform proper conversion, at the cost of efficiency.</li>
|
||||
|
||||
- Similarly, C-side code which deals with strings which might not be
|
||||
NUL-terminated (e.g. while tokenizing in FTS5-related code) cannot
|
||||
use JNI's new-string functions to return them to Java because none
|
||||
of those APIs take a string-length argument. Such cases must
|
||||
return byte arrays instead of strings.
|
||||
<li>C functions which take C-style strings without a length argument
|
||||
require special care when taking input from Java. In particular,
|
||||
Java strings converted to byte arrays for encoding purposes are not
|
||||
NUL-terminated, and conversion to a Java byte array must be careful
|
||||
to add one. Functions which take a length do not require this so
|
||||
long as the length is provided. Search the SQLite3Jni class for "\0"
|
||||
for many examples.
|
||||
|
||||
Further reading:
|
||||
<li>Similarly, C-side code which deals with strings which might not
|
||||
be NUL-terminated (e.g. while tokenizing in FTS5-related code)
|
||||
cannot use JNI's new-string functions to return them to Java because
|
||||
none of those APIs take a string-length argument. Such cases must
|
||||
return byte arrays instead of strings.
|
||||
|
||||
- https://stackoverflow.com/questions/57419723
|
||||
- https://stackoverflow.com/questions/7921016
|
||||
- https://itecnote.com/tecnote/java-getting-true-utf-8-characters-in-java-jni/
|
||||
- https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#unicode
|
||||
- https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8
|
||||
</ul>
|
||||
|
||||
<p>Further reading:
|
||||
|
||||
<p><a href="https://stackoverflow.com/questions/57419723">https://stackoverflow.com/questions/57419723</a>
|
||||
<p><a href="https://stackoverflow.com/questions/7921016">https://stackoverflow.com/questions/7921016</a>
|
||||
<p><a href="https://itecnote.com/tecnote/java-getting-true-utf-8-characters-in-java-jni/">https://itecnote.com/tecnote/java-getting-true-utf-8-characters-in-java-jni/</a>
|
||||
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#unicode">https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#unicode</a>
|
||||
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8">https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8</a>
|
||||
|
||||
*/
|
||||
public final class SQLite3Jni {
|
||||
@@ -124,7 +126,7 @@ public final class SQLite3Jni {
|
||||
This will clean up any cached per-JNIEnv info. Calling into the
|
||||
library will re-initialize the cache on demand.
|
||||
|
||||
This process does _not_ close any databases or finalize
|
||||
This process does not close any databases or finalize
|
||||
any prepared statements because their ownership does not depend on
|
||||
a given thread. For proper library behavior, and to
|
||||
avoid C-side leaks, be sure to finalize all statements and close
|
||||
@@ -1194,7 +1196,7 @@ public final class SQLite3Jni {
|
||||
|
||||
/**
|
||||
Internal impl of the public sqlite3_strglob() method. Neither argument
|
||||
may be NULL and both _MUST_ be NUL-terminated.
|
||||
may be NULL and both MUST be NUL-terminated.
|
||||
*/
|
||||
private static native int sqlite3_strglob(
|
||||
@NotNull byte[] glob, @NotNull byte[] txt
|
||||
@@ -1211,7 +1213,7 @@ public final class SQLite3Jni {
|
||||
|
||||
/**
|
||||
Internal impl of the public sqlite3_strlike() method. Neither
|
||||
argument may be NULL and both _MUST_ be NUL-terminated.
|
||||
argument may be NULL and both MUST be NUL-terminated.
|
||||
*/
|
||||
private static native int sqlite3_strlike(
|
||||
@NotNull byte[] glob, @NotNull byte[] txt, int escChar
|
||||
@@ -1319,10 +1321,11 @@ public final class SQLite3Jni {
|
||||
|
||||
/**
|
||||
This is NOT part of the public API. It exists solely as a place
|
||||
to hook in arbitrary C-side code during development and testing
|
||||
of this library.
|
||||
for this code's developers to collect internal metrics and such.
|
||||
It has no stable interface. It may go way or change behavior at
|
||||
any time.
|
||||
*/
|
||||
public static native void sqlite3_do_something_for_developer();
|
||||
public static native void sqlite3_jni_internal_details();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// SQLITE_... constants follow...
|
||||
|
||||
@@ -1575,7 +1575,7 @@ public class Tester1 implements Runnable {
|
||||
outln("\tAssertions checked: ",affirmCount);
|
||||
outln("\tDatabases opened: ",metrics.dbOpen);
|
||||
if( doSomethingForDev ){
|
||||
sqlite3_do_something_for_developer();
|
||||
sqlite3_jni_internal_details();
|
||||
}
|
||||
sqlite3_shutdown();
|
||||
int nMethods = 0;
|
||||
|
||||
6
ext/jni/src/org/sqlite/jni/package-info.java
Normal file
6
ext/jni/src/org/sqlite/jni/package-info.java
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
This package houses a JNI binding to the SQLite3 C API.
|
||||
|
||||
The docs are in progress.
|
||||
*/
|
||||
package org.sqlite.jni;
|
||||
@@ -629,7 +629,7 @@ public class SQLTester {
|
||||
t.outln("Aborted ",t.nAbortedScript," script(s).");
|
||||
}
|
||||
if( dumpInternals ){
|
||||
sqlite3_do_something_for_developer();
|
||||
sqlite3_jni_internal_details();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
manifest
25
manifest
@@ -1,5 +1,5 @@
|
||||
C Doc,\scode\sstyle,\sand\slegibility\scleanups.
|
||||
D 2023-08-24T17:25:05.398
|
||||
C More\scode\slegibility\sand\sstyle\simprovements\sin\sthe\sJNI\spieces.\sStart\swork\son\sa\sjavadoc\sbuild.
|
||||
D 2023-08-24T18:43:25.053
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -232,11 +232,11 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
|
||||
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
||||
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
||||
F ext/jni/GNUmakefile 2e17aae8debf0b0ee12010500eae7bd9557f8ad5554f0161c39a41f229e84e3e
|
||||
F ext/jni/GNUmakefile 6b3c0fd8d055c129735702d0b288589d25544dd404a00d46d9eb43770fe7f78f
|
||||
F ext/jni/README.md 9d3caa2e038bfe5e8356a9e8ff66f93ca0647ac278339eeea296f10017f5cf35
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c 1da808c65c101d603bc4d8c755aff618c6ce9331b79ef431128ff076cdfca8f7
|
||||
F ext/jni/src/c/sqlite3-jni.h d1ee39fe20cb5ac189c5b4c3afa5ff47e259ccfed006eee629c2fdf9fc474856
|
||||
F ext/jni/src/c/sqlite3-jni.c 8db2fcc05dd7749f9f4175e2654344feccac6abfd19fd9db0d116c6350e3b625
|
||||
F ext/jni/src/c/sqlite3-jni.h 2b81cfb83933cb18e5f690487f4556591d3329538809c847d00190aa4d69aa1d
|
||||
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
|
||||
F ext/jni/src/org/sqlite/jni/AutoExtension.java bcc1849b2fccbe5e2d7ac9e9ac7f8d05a6d7088a8fedbaad90e39569745a61e6
|
||||
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
|
||||
@@ -255,10 +255,10 @@ F ext/jni/src/org/sqlite/jni/PreUpdateHook.java dec00a706b58c67989f0ff56c4f0a703
|
||||
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495380677e87daa29a1c57a0e2c06b0a131dc
|
||||
F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
|
||||
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
|
||||
F ext/jni/src/org/sqlite/jni/SQLFunction.java f697cf2a81c4119f2baf0682af689686f0466f1dd83dba00885f5603e693fe16
|
||||
F ext/jni/src/org/sqlite/jni/SQLFunction.java 5851698d96ee29171d68930ad758d0f5a253f7575f1feb890d82b2557a8d3ef5
|
||||
F ext/jni/src/org/sqlite/jni/SQLLog.java c60610b35208416940822e834d61f08fbbe5d6e06b374b541b49e41fd56c9798
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java eaf6a3d6814465c2a9e67d6b32a4af2b8efaaa69cf905f8bb81c05222bfaf602
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java 3fcc891398e412fdbd49b40140c1ded83991218d396016184237bf74e1bc18c5
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java d96f10a097c1d614b44353e85a65368d9aca565d5ae57fae0104811594fbdfba
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java 76f308ad9bf0bd74374561c30c65564ed24583a465264b751d9e2333980149f1
|
||||
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
|
||||
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
|
||||
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
|
||||
@@ -266,11 +266,12 @@ F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71
|
||||
F ext/jni/src/org/sqlite/jni/fts5_api.java 5198be71c162e3e0cb1f4962a7cdf0d7596e8af53f70c4af6db24aab8d53d9ba
|
||||
F ext/jni/src/org/sqlite/jni/fts5_extension_function.java ac825035d7d83fc7fd960347abfa6803e1614334a21533302041823ad5fc894c
|
||||
F ext/jni/src/org/sqlite/jni/fts5_tokenizer.java e530b36e6437fcc500e95d5d75fbffe272bdea20d2fac6be2e1336c578fba98b
|
||||
F ext/jni/src/org/sqlite/jni/package-info.java 1a547913d681411d65c5fe0bca840f049abe5612740154a125545ea9e2481747
|
||||
F ext/jni/src/org/sqlite/jni/sqlite3.java 62b1b81935ccf3393472d17cb883dc5ff39c388ec3bc1de547f098a0217158fc
|
||||
F ext/jni/src/org/sqlite/jni/sqlite3_context.java fe7797a696978f057528a57b7a11e7797ed41fd7afcf100c5ebb67055d9f706f
|
||||
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 78e6d1b95ac600a9475e9db4623f69449322b0c93d1bd4e1616e76ed547ed9fc
|
||||
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
|
||||
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 2835eb3dd1e14767ca49354c224150c70300d8013d6d51dd875f7d9380faa278
|
||||
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java bc3d6797a2f6cb7d443a0b72af84e5a45e0416b96af52e432d28e123db1970c3
|
||||
F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
|
||||
F ext/jni/src/tests/000-000-sanity.test cfe6dc1b950751d6096e3f5695becaadcdaa048bfe9567209d6eb676e693366d
|
||||
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
|
||||
@@ -2094,8 +2095,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 862f9828e078ae138c3533658c45e4c45155975794e752b9b3a71a693842f37a
|
||||
R eb32cfcd718e24e179eb7f83fffb0fa5
|
||||
P cf185bcd25629d882a030b8b87048179a120ab1f84aa1d68b279c499dbdf0dba
|
||||
R 409ebb8571a40aa1108ef1efd5f91432
|
||||
U stephan
|
||||
Z 2f5c08343242711ee223d20d111fc13d
|
||||
Z 85677113ed9046ae48bf181600ab6418
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
cf185bcd25629d882a030b8b87048179a120ab1f84aa1d68b279c499dbdf0dba
|
||||
62b404d62fd62f4d220838b59c9f38a71afa2d4a8c3af0a5c9495fa7020972cf
|
||||
Reference in New Issue
Block a user