1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-24 22:22:08 +03:00

Start including fts5 customization bits into JNI, but it's far from functional.

FossilOrigin-Name: abaf5edd0430e3301a11bd0acb9ce4b81b310237e1799701411db56ef7605e01
This commit is contained in:
stephan
2023-08-04 11:08:25 +00:00
parent e133a0ec05
commit c0952c11a7
5 changed files with 104 additions and 48 deletions

View File

@ -35,10 +35,11 @@ sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
.NOTPARALLEL: $(sqlite3-jni.h)
SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java
SQLite3Jni.class := $(subst .java,.class,$(SQLite3Jni.java))
#$(sqlite3-jni.h): $(SQLite3Jni.java) $(dir.bld.c)
# $(bin.javac) -h $(dir $@) $<
#all: $(sqlite3-jni.h)
########################################################################
# The future of FTS5 customization in this API is as yet unclear.
# It would be a real doozy to bind to JNI.
enable.fts5 ?= 1
# Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae.
@ -62,6 +63,13 @@ JAVA_FILES := $(patsubst %,$(dir.src.jni)/%,\
UpdateHook.java \
ValueHolder.java \
)
ifeq (1,$(enable.fts5))
JAVA_FILES += $(patsubst %,$(dir.src.jni)/%,\
Fts5Context.java \
Fts5ExtensionApi.java \
Fts5Function.java \
)
endif
CLASS_FILES :=
define DOTCLASS_DEPS
$(1).class: $(1).java
@ -111,7 +119,6 @@ $(sqlite3.h):
$(sqlite3.c): $(sqlite3.h)
SQLITE_OPT := \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
@ -133,6 +140,10 @@ SQLITE_OPT := \
# for a var which gets set in all builds but only read
# via assert().
ifeq (1,$(enable.fts5))
SQLITE_OPT += -DSQLITE_ENABLE_FTS5
endif
sqlite3-jni.c := $(dir.src.c)/sqlite3-jni.c
sqlite3-jni.o := $(dir.bld.c)/sqlite3-jni.o
sqlite3-jni.h.in := $(dir.bld.c)/org_sqlite_jni_SQLite3Jni.h
@ -160,7 +171,7 @@ sqlite3-jni.dll.cflags := \
$(sqlite3-jni.h.in): $(dir.src.jni)/SQLite3Jni.class
$(sqlite3-jni.h): $(sqlite3-jni.h.in) $(MAKEFILE)
cp -p $(sqlite3-jni.h.in) $@
cat $(sqlite3-jni.h.in) > $@
$(sqlite3-jni.c): $(sqlite3-jni.h) $(sqlite3.c) $(sqlite3.h)
$(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
$(CC) $(sqlite3-jni.dll.cflags) $(SQLITE_OPT) \

View File

@ -57,8 +57,10 @@
#ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
# define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
#endif
#ifndef SQLITE_ENABLE_FTS4
# define SQLITE_ENABLE_FTS4 1
#ifdef SQLITE_ENABLE_FTS5
# ifndef SQLITE_ENABLE_FTS4
# define SQLITE_ENABLE_FTS4 1
# endif
#endif
#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
# define SQLITE_ENABLE_MATH_FUNCTIONS 1
@ -180,10 +182,13 @@
/** Helpers for extracting pointers from jobjects, noting that the
corresponding Java interfaces have already done the type-checking.
*/
#define PtrGet_sqlite3(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3)
#define PtrGet_sqlite3_stmt(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_stmt)
#define PtrGet_sqlite3_value(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_value)
#define PtrGet_sqlite3_context(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_context)
#define PtrGet_sqlite3(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3)
#define PtrGet_sqlite3_stmt(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_stmt)
#define PtrGet_sqlite3_value(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_value)
#define PtrGet_sqlite3_context(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_context)
#ifdef SQLITE_ENABLE_FTS5
#define PtrGet_Fts5Context(OBJ) getNativePointer(env,OBJ,S3ClassNames.Fts5Context)
#endif
/* Helpers for Java value reference management. */
#define REF_G(VAR) (*env)->NewGlobalRef(env, VAR)
#define REF_L(VAR) (*env)->NewLocalRef(env, VAR)
@ -200,12 +205,20 @@ static const struct {
const char * const sqlite3_context;
const char * const sqlite3_value;
const char * const OutputPointer_Int32;
} ClassNames = {
#ifdef SQLITE_ENABLE_FTS5
const char * const Fts5Context;
const char * const Fts5ExtensionApi;
#endif
} S3ClassNames = {
"org/sqlite/jni/sqlite3",
"org/sqlite/jni/sqlite3_stmt",
"org/sqlite/jni/sqlite3_context",
"org/sqlite/jni/sqlite3_value",
"org/sqlite/jni/OutputPointer$Int32"
"org/sqlite/jni/OutputPointer$Int32",
#ifdef SQLITE_ENABLE_FTS5
"org/sqlite/jni/Fts5Context",
"org/sqlite/jni/Fts5ExtensionApi"
#endif
};
/** Create a trivial JNI wrapper for (int CName(void)). */
@ -286,11 +299,11 @@ enum {
Need enough space for (only) the library's NativePointerHolder
types, a fixed count known at build-time. If we add more than this
a fatal error will be triggered with a reminder to increase this.
This value needs to be at least the number of entries in the
ClassNames object, as that value is our upper limit. The
ClassNames entries are the keys for this particular cache.
This value needs to be, at most, the number of entries in the
S3ClassNames object, as that value is our upper limit. The
S3ClassNames entries are the keys for this particular cache.
*/
NphCache_SIZE = sizeof(ClassNames) / sizeof(char const *)
NphCache_SIZE = sizeof(S3ClassNames) / sizeof(char const *)
};
/**
@ -299,7 +312,7 @@ enum {
typedef struct NphCacheLine NphCacheLine;
struct NphCacheLine {
const char * zClassName /* "full/class/Name". Must be a static string
from the ClassNames struct. */;
from the S3ClassNames struct. */;
jclass klazz /* global ref to concrete NativePointerHolder class */;
jmethodID midCtor /* klazz's constructor */;
jfieldID fidValue /* NativePointerHolder.nativePointer and OutputPointer.X.value */;
@ -327,6 +340,9 @@ struct JNIEnvCacheLine {
accounted for, so it may be best to
redefine the tracing API rather than
passing through the statement handles. */;
#ifdef SQLITE_ENABLE_FTS5
jobject jFts5Ext /* Java singleton for the Fts5ExtensionApi instance. */;
#endif
#if 0
/* TODO: refactor this cache as a linked list with malloc()'d entries,
rather than a fixed-size array in S3Global.envCache */
@ -525,7 +541,7 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj, jclass klazz){
If it does, we can dynamically allocate these instead.
*/
FIXME_THREADING
static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * const env){
struct JNIEnvCacheLine * row = 0;
int i = 0;
for( ; i < JNIEnvCache_SIZE; ++i ){
@ -541,6 +557,7 @@ static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
(*env)->FatalError(env, "Maintenance required: JNIEnvCache is full.");
return NULL;
}
memset(row, 0, sizeof(JNIEnvCacheLine));
row->env = env;
row->globalClassObj = REF_G((*env)->FindClass(env,"java/lang/Object"));
row->globalClassLong = REF_G((*env)->FindClass(env,"java/lang/Long"));
@ -635,7 +652,7 @@ static jfieldID getNativePointerField(JNIEnv * const env, jclass klazz){
zClassName must be a static string so we can use its address
as a cache key.
*/
static void setNativePointer(JNIEnv * env, jobject ppOut, void * p,
static void setNativePointer(JNIEnv * env, jobject ppOut, const void * p,
const char *zClassName){
jfieldID setter = 0;
struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName);
@ -655,7 +672,7 @@ static void setNativePointer(JNIEnv * env, jobject ppOut, void * p,
}
}
(*env)->SetLongField(env, ppOut, setter, (jlong)p);
IFTHREW_REPORT;
EXCEPTION_IS_FATAL("Could not set NativePointerHolder.nativePointer.");
}
/**
@ -858,6 +875,7 @@ static void PerDbStateJni_free_all(void){
}
}
/**
Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
This function calls sqlite3_aggregate_context() to allocate a tiny
@ -883,7 +901,7 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
void * pAgg;
int rc = 0;
struct NphCacheLine * const cacheLine =
S3Global_nph_cache(env, ClassNames.sqlite3_context);
S3Global_nph_cache(env, S3ClassNames.sqlite3_context);
if(cacheLine && cacheLine->klazz && cacheLine->fidSetAgg){
member = cacheLine->fidSetAgg;
assert(member);
@ -914,23 +932,23 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
return rc;
}
/* Sets a native int32 value in OutputPointer.Int32 object ppOut. */
static void setOutputInt32(JNIEnv * env, jobject ppOut, int v){
/* Sets a native int32 value in OutputPointer.Int32 object jOut. */
static void setOutputInt32(JNIEnv * env, jobject jOut, int v){
jfieldID setter = 0;
struct NphCacheLine * const cacheLine =
S3Global_nph_cache(env, ClassNames.OutputPointer_Int32);
S3Global_nph_cache(env, S3ClassNames.OutputPointer_Int32);
if(cacheLine && cacheLine->klazz && cacheLine->fidValue){
setter = cacheLine->fidValue;
}else{
const jclass klazz = (*env)->GetObjectClass(env, ppOut);
const jclass klazz = (*env)->GetObjectClass(env, jOut);
setter = (*env)->GetFieldID(env, klazz, "value", "I");
if(cacheLine){
assert(!cacheLine->fidValue);
cacheLine->fidValue = setter;
}
}
(*env)->SetIntField(env, ppOut, setter, (jint)v);
IFTHREW_REPORT;
(*env)->SetIntField(env, jOut, setter, (jint)v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}
static int encodingTypeIsValid(int eTextRep){
@ -1053,7 +1071,7 @@ static void ResultJavaVal_finalizer(void *v){
its address as a cache key.
*/
static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zClassName,
void * pNative){
const void * pNative){
jobject rv = 0;
jclass klazz = 0;
jmethodID ctor = 0;
@ -1067,7 +1085,8 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zC
klazz = cacheLine
? cacheLine->klazz
: (*env)->FindClass(env, zClassName);
ctor = (*env)->GetMethodID(env, klazz, "<init>", "()V");
ctor = klazz ? (*env)->GetMethodID(env, klazz, "<init>", "()V") : 0;
EXCEPTION_IS_FATAL("Cannot find constructor for class.");
if(cacheLine){
assert(zClassName == cacheLine->zClassName);
assert(cacheLine->klazz);
@ -1078,22 +1097,43 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zC
assert(klazz);
assert(ctor);
rv = (*env)->NewObject(env, klazz, ctor);
EXCEPTION_IS_FATAL("No-arg constructor threw.");
if(rv) setNativePointer(env, rv, pNative, zClassName);
return rv;
}
static jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3_value", sv);
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_value, sv);
}
static jobject new_sqlite3_context_wrapper(JNIEnv * const env, sqlite3_context *sv){
return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3_context", sv);
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_context, sv);
}
static jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, sqlite3_stmt *sv){
return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3_stmt", sv);
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_stmt, sv);
}
#if 0
#ifdef SQLITE_ENABLE_FTS5
static jobject new_Fts5Context_wrapper(JNIEnv * const env, Fts5Context *sv){
return new_NativePointerHolder_object(env, S3ClassNames.Fts5Context, sv);
}
#endif
#endif
#ifdef SQLITE_ENABLE_FTS5
/*static*/ jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
JNIEnvCacheLine * const row = S3Global_env_cache(env);
if( !row->jFts5Ext ){
row->jFts5Ext = new_NativePointerHolder_object(env, S3ClassNames.Fts5ExtensionApi,
&sFts5Api/*from sqlite3.c*/);
if(row->jFts5Ext) row->jFts5Ext = REF_G(row->jFts5Ext);
}
return row->jFts5Ext;
}
#endif
enum UDFType {
UDF_SCALAR = 1,
UDF_AGGREGATE,
@ -1498,7 +1538,7 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb);
if(ps) PerDbStateJni_set_aside(ps)
/* MUST come after close() because of ps->trace. */;
setNativePointer(env, jDb, 0, ClassNames.sqlite3);
setNativePointer(env, jDb, 0, S3ClassNames.sqlite3);
return (jint)rc;
}
@ -1891,7 +1931,7 @@ JDECL(jint,1finalize)(JENV_JSELF, jobject jpStmt){
JNIEnvCacheLine * const jc = S3Global_env_cache(env);
jobject const pPrev = stmt_set_current(jc, jpStmt);
rc = sqlite3_finalize(pStmt);
setNativePointer(env, jpStmt, 0, ClassNames.sqlite3_stmt);
setNativePointer(env, jpStmt, 0, S3ClassNames.sqlite3_stmt);
(void)stmt_set_current(jc, pPrev);
}
return rc;
@ -1921,7 +1961,7 @@ static int s3jni_open_post(JNIEnv * const env, sqlite3 **ppDb, jobject jDb, int
theRc = SQLITE_NOMEM;
}
}
setNativePointer(env, jDb, *ppDb, ClassNames.sqlite3);
setNativePointer(env, jDb, *ppDb, S3ClassNames.sqlite3);
return theRc;
}
@ -1983,7 +2023,7 @@ static jint sqlite3_jni_prepare_v123(int prepVersion, JNIEnv * const env, jclass
assert(zTail ? (((int)((void*)zTail - (void*)pBuf)) >= 0) : 1);
setOutputInt32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
}
setNativePointer(env, jOutStmt, pStmt, ClassNames.sqlite3_stmt);
setNativePointer(env, jOutStmt, pStmt, S3ClassNames.sqlite3_stmt);
(void)stmt_set_current(jc, pOldStmt);
return (jint)rc;
}
@ -2249,8 +2289,9 @@ JDECL(void,1set_1last_1insert_1rowid)(JENV_JSELF, jobject jpDb, jlong rowId){
JDECL(jint,1shutdown)(JENV_JSELF){
PerDbStateJni_free_all();
JNIEnvCache_clear(&S3Global.envCache);
/* Do not clear S3Global.jvm: it's legal to call
sqlite3_initialize() again to restart the lib. */
/* Do not clear S3Global.jvm or the global refs to specific classes:
it's legal to call sqlite3_initialize() again to restart the
lib. */
return sqlite3_shutdown();
}

View File

@ -794,6 +794,10 @@ public final class SQLite3Jni {
public static native int sqlite3_value_subtype(@NotNull sqlite3_value v);
/**
Cleans up all per-JNIEnv and per-db state managed by the library
then calls the C-native sqlite3_shutdown().
*/
public static native int sqlite3_shutdown();
/**

View File

@ -1,5 +1,5 @@
C Improve\sinternal\serror\shandling\sin\sthe\sJNI\screate_function()\simpl.
D 2023-08-04T09:53:13.893
C Start\sincluding\sfts5\scustomization\sbits\sinto\sJNI,\sbut\sit's\sfar\sfrom\sfunctional.
D 2023-08-04T11:08:25.675
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -230,9 +230,9 @@ 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 7b7bcd691abe0567e914b1964804efe3ebbecdd86a05c324365ed00ce632be8f
F ext/jni/GNUmakefile 4497a2f82b5d95cb409d9207f7d82c54f100eeb0cc2b05aa05e806566b6a38a1
F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf
F ext/jni/src/c/sqlite3-jni.c d74352df0bad94caa6a239f5730d7f5c7669aa178c37ab536006d3254c2f9c85
F ext/jni/src/c/sqlite3-jni.c 904404bc810a809c2ec7de9fc178d559ceb8c4310fec82629ac25107de3f0e28
F ext/jni/src/c/sqlite3-jni.h 74aaf87e77f99857aa3afc013517c934cbc2c16618c83d8f5d6294351bc8e7b1
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
@ -243,7 +243,7 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java c7868f1f4ad63435ee44d409377df7dd
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 0139a6174d26b7703fcfa10945fdab55f28f424e212b08964038e0bd83744e0f
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 78c079efc177d2975932fca9cfd34dd4d2c2062feae3f6f2016d0964e5a7120c
F ext/jni/src/org/sqlite/jni/Tester1.java 9443cdbd2b10f6a8e1f3abd1694983a16b17960f8ed2f7e06bcc7e535fb5abcf
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
@ -2071,8 +2071,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 306b269a01037bc5c98276276fdb17b37027d1ee0d603183f42a65966245bdff
R 6be22ebb8adf8ecf4f94561b29aff52e
P 2c88390faa108a60c8fb1eb7aad05d90f3daf4cfef14ca73987597aaf7be83c9
R 8bcf0b9bad61c244dfd6aa8e17b480b1
U stephan
Z ade457d4f3c6fece0dffd75e56e9b6b4
Z a12eb6e80e9b1d3771520cdb25f8972d
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
2c88390faa108a60c8fb1eb7aad05d90f3daf4cfef14ca73987597aaf7be83c9
abaf5edd0430e3301a11bd0acb9ce4b81b310237e1799701411db56ef7605e01