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

More work on the JNI binding of fts5 customization (still a long ways to go).

FossilOrigin-Name: 1a246fd21657f5bb13eeacc4059894ab787ea9a3c45bd9bdd3030a66643d2fef
This commit is contained in:
stephan
2023-08-04 15:38:59 +00:00
parent c7795cfd47
commit cc8202b646
6 changed files with 219 additions and 50 deletions

View File

@ -203,6 +203,8 @@ static const struct {
const char * const sqlite3_value;
const char * const OutputPointer_Int32;
const char * const OutputPointer_Int64;
const char * const OutputPointer_String;
const char * const OutputPointer_ByteArray;
#ifdef SQLITE_ENABLE_FTS5
const char * const Fts5Context;
const char * const Fts5ExtensionApi;
@ -215,6 +217,8 @@ static const struct {
"org/sqlite/jni/sqlite3_value",
"org/sqlite/jni/OutputPointer$Int32",
"org/sqlite/jni/OutputPointer$Int64",
"org/sqlite/jni/OutputPointer$String",
"org/sqlite/jni/OutputPointer$ByteArray",
#ifdef SQLITE_ENABLE_FTS5
"org/sqlite/jni/Fts5Context",
"org/sqlite/jni/Fts5ExtensionApi",
@ -941,21 +945,33 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
return rc;
}
/* Sets a native int32 value in OutputPointer.Int32 object jOut. */
static void setOutputInt32(JNIEnv * env, jobject jOut, int v){
/**
Common init for setOutputInt32() and friends.
*/
static void setupOutputPointer(JNIEnv * env, const char *zClassName,
const char *zTypeSig,
jobject jOut, jfieldID * pSetter){
jfieldID setter = 0;
struct NphCacheLine * const cacheLine =
S3Global_nph_cache(env, S3ClassNames.OutputPointer_Int32);
S3Global_nph_cache(env, zClassName);
if(cacheLine && cacheLine->klazz && cacheLine->fidValue){
setter = cacheLine->fidValue;
}else{
const jclass klazz = (*env)->GetObjectClass(env, jOut);
setter = (*env)->GetFieldID(env, klazz, "value", "I");
setter = (*env)->GetFieldID(env, klazz, "value", zTypeSig);
EXCEPTION_IS_FATAL("setupOutputPointer() could not find OutputPointer.*.value");
if(cacheLine){
assert(!cacheLine->fidValue);
cacheLine->fidValue = setter;
}
}
*pSetter = setter;
}
/* Sets a native int32 value in OutputPointer.Int32 object jOut. */
static void setOutputInt32(JNIEnv * env, jobject jOut, int v){
jfieldID setter = 0;
setupOutputPointer(env, S3ClassNames.OutputPointer_Int32, "I", jOut, &setter);
(*env)->SetIntField(env, jOut, setter, (jint)v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}
@ -964,21 +980,34 @@ static void setOutputInt32(JNIEnv * env, jobject jOut, int v){
/* 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);
setupOutputPointer(env, S3ClassNames.OutputPointer_Int64, "J", jOut, &setter);
(*env)->SetLongField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int64.value");
}
static void setOutputByteArray(JNIEnv * env, jobject jOut, jbyteArray v){
jfieldID setter = 0;
setupOutputPointer(env, S3ClassNames.OutputPointer_ByteArray, "[B",
jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.ByteArray.value");
}
#if 0
/* Sets a String value in OutputPointer.String object jOut. */
static void setOutputString(JNIEnv * env, jobject jOut, jstring v){
jfieldID setter = 0;
setupOutputPointer(env, S3ClassNames.OutputPointer_String, "Ljava/lang/String",
jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.String.value");
}
static void setOutputString2(JNIEnv * env, jobject jOut, const char * zStr){
jstring const jStr = (*env)->NewStringUTF(env, zStr);
if(jStr){
setOutputString(env, jOut, jStr);
UNREF_L(jStr);
}
}
#endif
#endif /* SQLITE_ENABLE_FTS5 */
static int encodingTypeIsValid(int eTextRep){
@ -2636,6 +2665,46 @@ JDECLFts(jint,xColumnCount)(JENV_JSELF,jobject jCtx){
return (jint)fext->xColumnCount(PtrGet_Fts5Context(jCtx));
}
JDECLFts(jint,xColumnSize)(JENV_JSELF,jobject jCtx, jint iIdx, jobject jOut32){
Fts5ExtDecl;
int n1 = 0;
int const rc = fext->xColumnSize(PtrGet_Fts5Context(jCtx), (int)iIdx, &n1);
if( 0==rc ) setOutputInt32(env, jOut32, n1);
return rc;
}
JDECLFts(jint,xColumnText)(JENV_JSELF,jobject jCtx, jint iCol,
jobject jOutBA){
Fts5ExtDecl;
const char *pz = 0;
int pn = 0;
int rc = fext->xColumnText(PtrGet_Fts5Context(jCtx), (int)iCol,
&pz, &pn);
if( 0==rc ){
/* Two problems here:
1) JNI doesn't give us a way to create strings from standard
UTF-8. We're converting the results to MUTF-8, which may
differ for exotic text.
2) JNI's NewStringUTF() (which treats its input as MUTF-8) does
not take a _length_ - it requires the string to be
NUL-terminated, which may not the case here.
So we use a byte array and convert it to UTF-8 Java-side.
*/
jbyteArray const jba = (*env)->NewByteArray(env, (jint)pn);
if( jba ){
(*env)->SetByteArrayRegion(env, jba, 0, (jint)pn, (const jbyte*)pz);
setOutputByteArray(env, jOutBA, jba);
UNREF_L(jba)/*jOutBA has a reference*/;
}else{
rc = SQLITE_NOMEM;
}
}
return (jint)rc;
}
JDECLFts(jint,xColumnTotalSize)(JENV_JSELF,jobject jCtx, jint iCol, jobject jOut64){
Fts5ExtDecl;
sqlite3_int64 nOut = 0;
@ -2644,6 +2713,27 @@ JDECLFts(jint,xColumnTotalSize)(JENV_JSELF,jobject jCtx, jint iCol, jobject jOut
return (jint)rc;
}
JDECLFts(jint,xInst)(JENV_JSELF,jobject jCtx, jint iIdx, jobject jOutPhrase,
jobject jOutCol, jobject jOutOff){
Fts5ExtDecl;
int n1 = 0, n2 = 2, n3 = 0;
int const rc = fext->xInst(PtrGet_Fts5Context(jCtx), (int)iIdx, &n1, &n2, &n3);
if( 0==rc ){
setOutputInt32(env, jOutPhrase, n1);
setOutputInt32(env, jOutCol, n2);
setOutputInt32(env, jOutOff, n3);
}
return rc;
}
JDECLFts(jint,xInstCount)(JENV_JSELF,jobject jCtx, jobject jOut32){
Fts5ExtDecl;
int nOut = 0;
int const rc = fext->xInstCount(PtrGet_Fts5Context(jCtx), &nOut);
if( 0==rc && jOut32 ) setOutputInt32(env, jOut32, nOut);
return (jint)rc;
}
JDECLFts(jint,xPhraseCount)(JENV_JSELF,jobject jCtx){
Fts5ExtDecl;
return (jint)fext->xPhraseCount(PtrGet_Fts5Context(jCtx));
@ -2662,6 +2752,11 @@ JDECLFts(jint,xRowCount)(JENV_JSELF,jobject jCtx, jobject jOut64){
return (jint)rc;
}
JDECLFts(jlong,xRowid)(JENV_JSELF,jobject jCtx){
Fts5ExtDecl;
return (jlong)fext->xRowid(PtrGet_Fts5Context(jCtx));
}
#endif /* SQLITE_ENABLE_FTS5 */
////////////////////////////////////////////////////////////////////////

View File

@ -1642,11 +1642,19 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnCount
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xRowCount
* Signature: (Lorg/sqlite/jni/Fts5Context;Lorg/sqlite/jni/OutputPointer/Int64;)I
* Method: xColumnSize
* Signature: (Lorg/sqlite/jni/Fts5Context;ILorg/sqlite/jni/OutputPointer/Int32;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xRowCount
(JNIEnv *, jobject, jobject, jobject);
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnSize
(JNIEnv *, jobject, jobject, jint, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xColumnText
* Signature: (Lorg/sqlite/jni/Fts5Context;ILorg/sqlite/jni/OutputPointer/ByteArray;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnText
(JNIEnv *, jobject, jobject, jint, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
@ -1656,6 +1664,22 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xRowCount
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xColumnTotalSize
(JNIEnv *, jobject, jobject, jint, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xInst
* Signature: (Lorg/sqlite/jni/Fts5Context;ILorg/sqlite/jni/OutputPointer/Int32;Lorg/sqlite/jni/OutputPointer/Int32;Lorg/sqlite/jni/OutputPointer/Int32;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xInst
(JNIEnv *, jobject, jobject, jint, jobject, jobject, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xInstCount
* Signature: (Lorg/sqlite/jni/Fts5Context;Lorg/sqlite/jni/OutputPointer/Int32;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xInstCount
(JNIEnv *, jobject, jobject, jobject);
/*
* Class: org_sqlite_jni_Fts5ExtensionApi
* Method: xPhraseCount
@ -1672,6 +1696,22 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xPhraseCount
JNIEXPORT jint JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xPhraseSize
(JNIEnv *, jobject, jobject, jint);
/*
* 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: xRowid
* Signature: (Lorg/sqlite/jni/Fts5Context;)J
*/
JNIEXPORT jlong JNICALL Java_org_sqlite_jni_Fts5ExtensionApi_xRowid
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif

View File

@ -12,6 +12,7 @@
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
import java.nio.charset.StandardCharsets;
/**
FAR FROM COMPLETE and the feasibility of binding this to Java
@ -26,12 +27,34 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
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);
/**************************************************************
public native int xColumnCount(@NotNull Fts5Context fcx);
public native int xColumnSize(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.Int32 pnToken);
public native int xColumnText(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.ByteArray txt);
public int xColumnText(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.String txt){
final OutputPointer.ByteArray out = new OutputPointer.ByteArray();
int rc = xColumnText(cx, iCol, out);
if( 0 == rc ){
txt.setValue( new String(out.getValue(), StandardCharsets.UTF_8) );
}
return rc;
}
public native int xColumnTotalSize(@NotNull Fts5Context fcx, int iCol,
@NotNull OutputPointer.Int64 pnToken);
public native int xInst(@NotNull Fts5Context cx, int iIdx,
@NotNull OutputPointer.Int32 piPhrase,
@NotNull OutputPointer.Int32 piCol,
@NotNull OutputPointer.Int32 piOff);
public native int xInstCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int32 pnInst);
public native int xPhraseCount(@NotNull Fts5Context fcx);
public native int xPhraseSize(@NotNull Fts5Context fcx, int iPhrase);
public native int xRowCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int64 nRow);
public native long xRowid(@NotNull Fts5Context cx);
/**************************************************************
void *(*xUserData)(Fts5Context*);
int (*xTokenize)(Fts5Context*,
@ -40,15 +63,6 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
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*)

View File

@ -15,8 +15,7 @@ package org.sqlite.jni;
/**
Helper classes for handling JNI output pointers for primitive
types. Higher-level classes which use output pointers have their
own corresponding Java class, e.g. sqlite3 and sqlite3_stmt.
types.
We do not use a generic OutputPointer<T> because working with those
from the native JNI code is unduly quirky due to a lack of
@ -24,13 +23,34 @@ package org.sqlite.jni;
*/
public final class OutputPointer {
public static final class Int32 {
//! Only set from the JNI layer.
private int value;
Int32(){this(0);}
Int32(int v){value = v;}
public final int getValue(){return value;}
public final void setValue(int v){value = v;}
}
public static final class Int64 {
//! Only set from the JNI layer.
private long value;
Int64(){this(0);}
Int64(long v){value = v;}
public final long getValue(){return value;}
public final void setValue(long v){value = v;}
}
public static final class String {
private java.lang.String value;
String(){this(null);}
String(java.lang.String v){value = v;}
public final java.lang.String getValue(){return value;}
public final void setValue(java.lang.String v){value = v;}
}
public static final class ByteArray {
private byte value[];
ByteArray(){this(null);}
ByteArray(byte v[]){value = v;}
public final byte[] getValue(){return value;}
public final void setValue(byte v[]){value = v;}
}
}