1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

More work towards binding FTS5 customization to JNI. Add Fts*.java files missing from previous checkin.

FossilOrigin-Name: 91263178f463ca4623dd0203696eff6bcfd68abde5d2471be3f5a3edd791c52a
This commit is contained in:
stephan
2023-08-04 12:44:06 +00:00
parent c0952c11a7
commit b15223bce6
11 changed files with 334 additions and 51 deletions

View File

@ -186,9 +186,6 @@
#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)
@ -205,6 +202,7 @@ static const struct {
const char * const sqlite3_context;
const char * const sqlite3_value;
const char * const OutputPointer_Int32;
const char * const OutputPointer_Int64;
#ifdef SQLITE_ENABLE_FTS5
const char * const Fts5Context;
const char * const Fts5ExtensionApi;
@ -215,9 +213,11 @@ static const struct {
"org/sqlite/jni/sqlite3_context",
"org/sqlite/jni/sqlite3_value",
"org/sqlite/jni/OutputPointer$Int32",
"org/sqlite/jni/OutputPointer$Int64",
#ifdef SQLITE_ENABLE_FTS5
"org/sqlite/jni/Fts5Context",
"org/sqlite/jni/Fts5ExtensionApi"
"org/sqlite/jni/fts5_api"
#endif
};
@ -335,13 +335,12 @@ struct JNIEnvCacheLine {
sqlite3_stmt wrapper object for every
tracing call which needs a stmt
object. This approach is rather invasive,
however, and there may well be places
tracing may trigger which we have no
accounted for, so it may be best to
redefine the tracing API rather than
passing through the statement handles. */;
however, requiring code in all stmt
operations which can lead through the
tracing API. */;
#ifdef SQLITE_ENABLE_FTS5
jobject jFts5Ext /* Java singleton for the Fts5ExtensionApi instance. */;
jobject jFtsExt /* Global ref to Java singleton for the
Fts5ExtensionApi instance. */;
#endif
#if 0
/* TODO: refactor this cache as a linked list with malloc()'d entries,
@ -368,6 +367,9 @@ static void JNIEnvCacheLine_clear(JNIEnvCacheLine * const p){
if(env){
UNREF_G(p->globalClassObj);
UNREF_G(p->globalClassLong);
#ifdef SQLITE_ENABLE_FTS5
UNREF_G(p->jFtsExt);
#endif
i = 0;
for( ; i < NphCache_SIZE; ++i){
NphCacheLine_clear(env, &p->nph[i]);
@ -412,8 +414,9 @@ struct PerDbStateJni {
it would be a different instance (and maybe even a
different class) than the one the user may expect
to receive. */;
PerDbStateJni * pNext /* Next entry in the available/free list */;
PerDbStateJni * pPrev /* Previous entry in the available/free list */;
#ifdef SQLITE_ENABLE_FTS5
jobject jFtsApi /* global ref to fts5_api object for the db. */;
#endif
JniHookState busyHandler;
JniHookState collation;
JniHookState collationNeeded;
@ -422,6 +425,8 @@ struct PerDbStateJni {
JniHookState rollbackHook;
JniHookState trace;
JniHookState updateHook;
PerDbStateJni * pNext /* Next entry in the available/free list */;
PerDbStateJni * pPrev /* Previous entry in the available/free list */;
};
static struct {
@ -795,6 +800,9 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){
UNHOOK(busyHandler, 1);
#undef UNHOOK
UNREF_G(s->jDb);
#ifdef SQLITE_ENABLE_FTS5
UNREF_G(s->jFtsApi);
#endif
memset(s, 0, sizeof(PerDbStateJni));
s->pNext = S3Global.perDb.aFree;
if(s->pNext) s->pNext->pPrev = s;
@ -951,6 +959,25 @@ static void setOutputInt32(JNIEnv * env, jobject jOut, int v){
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}
/* Sets a native int64 value in OutputPointer.Int64 object jOut. */
static void setOutputInt64(JNIEnv * env, jobject jOut, jlong v){
jfieldID setter = 0;
struct NphCacheLine * const cacheLine =
S3Global_nph_cache(env, S3ClassNames.OutputPointer_Int64);
if(cacheLine && cacheLine->klazz && cacheLine->fidValue){
setter = cacheLine->fidValue;
}else{
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, jOut, setter, (jint)v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int64.value");
}
static int encodingTypeIsValid(int eTextRep){
switch(eTextRep){
case SQLITE_UTF8: case SQLITE_UTF16:
@ -1114,26 +1141,6 @@ static jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, 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,
@ -2582,11 +2589,83 @@ JDECL(void,1do_1something_1for_1developer)(JENV_JSELF){
#undef SO
}
////////////////////////////////////////////////////////////////////////
// End of the sqlite3_... API bindings. Next up, FTS5...
////////////////////////////////////////////////////////////////////////
#ifdef SQLITE_ENABLE_FTS5
/* Creates a verbose JNI Fts5 function name. */
#define JFuncNameFts5Ext(Suffix) \
Java_org_sqlite_jni_Fts5ExtensionApi_ ## Suffix
#define JDECLFts(ReturnType,Suffix) \
JNIEXPORT ReturnType JNICALL \
JFuncNameFts5Ext(Suffix)
#define PtrGet_Fts5Context(OBJ) getNativePointer(env,OBJ,S3ClassNames.Fts5Context)
static inline Fts5ExtensionApi const * s3jni_ftsext(void){
return &sFts5Api/*singleton from sqlite3.c*/;
}
#define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
#if 0
static jobject new_Fts5Context_wrapper(JNIEnv * const env, Fts5Context *sv){
return new_NativePointerHolder_object(env, S3ClassNames.Fts5Context, sv);
}
#endif
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
JNIEnvCacheLine * const row = S3Global_env_cache(env);
if( !row->jFtsExt ){
row->jFtsExt = new_NativePointerHolder_object(env, S3ClassNames.Fts5ExtensionApi,
s3jni_ftsext());
if(row->jFtsExt) row->jFtsExt = REF_G(row->jFtsExt);
}
return row->jFtsExt;
}
JDECLFts(jobject,getInstance)(JENV_JSELF){
return s3jni_getFts5ExensionApi(env);
}
JDECLFts(jint,xColumnCount)(JENV_JSELF,jobject jCtx){
Fts5ExtDecl;
return (jint)fext->xColumnCount(PtrGet_Fts5Context(jCtx));
}
JDECLFts(jint,xColumnTotalSize)(JENV_JSELF,jobject jCtx, jint iCol, jobject jOut64){
Fts5ExtDecl;
sqlite3_int64 nOut = 0;
int const rc = fext->xColumnTotalSize(PtrGet_Fts5Context(jCtx), (int)iCol, &nOut);
if( 0==rc && jOut64 ) setOutputInt64(env, jOut64, (jlong)nOut);
return (jint)rc;
}
JDECLFts(jint,xPhraseCount)(JENV_JSELF,jobject jCtx){
Fts5ExtDecl;
return (jint)fext->xPhraseCount(PtrGet_Fts5Context(jCtx));
}
JDECLFts(jint,xPhraseSize)(JENV_JSELF,jobject jCtx, jint iPhrase){
Fts5ExtDecl;
return (jint)fext->xPhraseSize(PtrGet_Fts5Context(jCtx), (int)iPhrase);
}
JDECLFts(jint,xRowCount)(JENV_JSELF,jobject jCtx, jobject jOut64){
Fts5ExtDecl;
sqlite3_int64 nOut = 0;
int const rc = fext->xRowCount(PtrGet_Fts5Context(jCtx), &nOut);
if( 0==rc && jOut64 ) setOutputInt64(env, jOut64, (jlong)nOut);
return (jint)rc;
}
#endif /* SQLITE_ENABLE_FTS5 */
////////////////////////////////////////////////////////////////////////
// End of the main API bindings. What follows are internal utilities.
////////////////////////////////////////////////////////////////////////
/**
Called during static init of the SQLite3Jni class to sync certain
compile-time constants to Java-space.

View File

@ -1615,3 +1615,64 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1do_1something_1fo
}
#endif
#endif
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_sqlite_jni_Fts5ExtensionApi */
#ifndef _Included_org_sqlite_jni_Fts5ExtensionApi
#define _Included_org_sqlite_jni_Fts5ExtensionApi
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: getInstance
* Signature: ()Lorg/sqlite/jni/Fts5ExtensionApi;
*/
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_getInstance
(JNIEnv *, jclass);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xColumnCount
* Signature: (Lorg/sqlite/jni/Fts5Context;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnCount
(JNIEnv *, jobject, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xRowCount
* Signature: (Lorg/sqlite/jni/Fts5Context;Lorg/sqlite/jni/OutputPointer/Int64;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xRowCount
(JNIEnv *, jobject, jobject, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xColumnTotalSize
* Signature: (Lorg/sqlite/jni/Fts5Context;ILorg/sqlite/jni/OutputPointer/Int64;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnTotalSize
(JNIEnv *, jobject, jobject, jint, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xPhraseCount
* Signature: (Lorg/sqlite/jni/Fts5Context;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xPhraseCount
(JNIEnv *, jobject, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xPhraseSize
* Signature: (Lorg/sqlite/jni/Fts5Context;I)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xPhraseSize
(JNIEnv *, jobject, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,23 @@
/*
** 2023-08-04
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
A wrapper for communicating C-level (Fts5Context*) instances with
Java. These wrappers do not own their associated pointer, they
simply provide a type-safe way to communicate it between Java and C
via JNI.
*/
public final class Fts5Context extends NativePointerHolder<Fts5Context> {
}

View File

@ -0,0 +1,65 @@
/*
** 2023-08-04
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
FAR FROM COMPLETE and the feasibility of binding this to Java
is still undetermined. This might be removed.
Reminder to self: the native Fts5ExtensionApi is a singleton.
*/
public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi> {
//! Only called from JNI
private Fts5ExtensionApi(){}
private int iVersion;
public static native Fts5ExtensionApi getInstance();
public native int xColumnCount(Fts5Context fcx);
public native int xRowCount(Fts5Context fcx, OutputPointer.Int64 nRow);
public native int xColumnTotalSize(Fts5Context fcx, int iCol, OutputPointer.Int64 pnToken);
public native int xPhraseCount(Fts5Context fcx);
public native int xPhraseSize(Fts5Context fcx, int iPhrase);
/**************************************************************
void *(*xUserData)(Fts5Context*);
int (*xTokenize)(Fts5Context*,
const char *pText, int nText,
void *pCtx,
int (*xToken)(void*, int, const char*, int, int, int)
);
int (*xPhraseCount)(Fts5Context*);
int (*xPhraseSize)(Fts5Context*, int iPhrase);
int (*xInstCount)(Fts5Context*, int *pnInst);
int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
sqlite3_int64 (*xRowid)(Fts5Context*);
int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
);
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
void *(*xGetAuxdata)(Fts5Context*, int bClear);
int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
**************************************************************/
}

View File

@ -0,0 +1,27 @@
/*
** 2023-08-04
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
Fts5Function is used in conjunction with the
sqlite3_create_fts_function() JNI-bound API to give that native code
access to the callback functions needed in order to implement
FTS5 auxiliary functions in Java.
*/
public abstract class Fts5Function {
public abstract void xFunction(Fts5ExtensionApi pApi, Fts5Context pFts,
sqlite3_context pCtx, sqlite3_value argv[]);
public void xDestroy() {}
}

View File

@ -776,14 +776,6 @@ public final class SQLite3Jni {
public static native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v);
//TODO: to_java() should return a closest-match type for the given
//value. The quirk is that it would need to return object-type values,
//e.g. Integer instead of int, and creating those is a bit of a nuisance
//from JNI.
//public static native Object sqlite3_value_to_java(@NotNull sqlite3_value v);
// Or we can just implement it in Java:
//public static Object sqlite3_value_to_java(@NotNull sqlite3_value v){...}
public static native int sqlite3_value_type(@NotNull sqlite3_value v);
public static native int sqlite3_value_numeric_type(@NotNull sqlite3_value v);

View File

@ -877,7 +877,6 @@ public class Tester1 {
sqlite3_close_v2(db);
}
private static void testRollbackHook(){
final sqlite3 db = createNewDb();
final ValueHolder<Integer> counter = new ValueHolder<>(0);
@ -910,6 +909,12 @@ public class Tester1 {
sqlite3_close_v2(db);
}
private static void testFts1(){
Fts5ExtensionApi fea = Fts5ExtensionApi.getInstance();
affirm( null != fea );
affirm( fea.getNativePointer() != 0 );
}
private static void testSleep(){
out("Sleeping briefly... ");
sqlite3_sleep(600);

View File

@ -0,0 +1,23 @@
/*
** 2023-08-04
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
/**
A wrapper for communicating C-level (fts5_api*) instances with
Java. These wrappers do not own their associated pointer, they
simply provide a type-safe way to communicate it between Java and C
via JNI.
*/
public final class fts5_api extends NativePointerHolder<fts5_api> {
}