diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 07b7dd2b5c..0a879383ca 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -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 */ //////////////////////////////////////////////////////////////////////// diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index aa2786f0c6..f39b7824f9 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -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 diff --git a/ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java b/ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java index d2a75e026f..a8ded85df4 100644 --- a/ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java +++ b/ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java @@ -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 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;} } } diff --git a/manifest b/manifest index a2402ef513..c7a09635a2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Eliminate\scode\sduplication\sin\sthe\stwo\sJNI\stester\sclasses. -D 2023-08-04T13:27:45.190 +C More\swork\son\sthe\sJNI\sbinding\sof\sfts5\scustomization\s(still\sa\slong\sways\sto\sgo). +D 2023-08-04T15:38:59.701 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,17 +232,17 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile 83f8f1c5a76714b3034815631587336c9b5bb345a325bde118a6909e2f18b16f F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf -F ext/jni/src/c/sqlite3-jni.c d3f98fa1b76d2ee810984ace183459d893d322f8c78bdf44d2bacf2b5e465cf6 -F ext/jni/src/c/sqlite3-jni.h ed03612024e9fe06a9e0655ccfe9f9f7bd899c7e68badad636c7d9833682655b +F ext/jni/src/c/sqlite3-jni.c e8bbc4773c06b25696efb7a714736b1598fd70234a536ba6e4c27dd698ecd087 +F ext/jni/src/c/sqlite3-jni.h c67b4299e349c364b2f13787d629b59c1690c9d2834d3daa6913eb8609bee9a7 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7 F ext/jni/src/org/sqlite/jni/CommitHook.java 87c6a8e5138c61a8eeff018fe16d23f29219150239746032687f245938baca1a F ext/jni/src/org/sqlite/jni/Fts5Context.java 0a5a02047a6a1dd3e4a38b0e542a8dd2de365033ba30e6ae019a676305959890 -F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java a1352e38eda4f0a78c51d4e1d71bacc7aa9bd9a47f4724626399079992ffdb1f +F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java 46fe8ebff4c42cc10259026cf37f77ebe82ba38fa961b49c012c0def3eb97925 F ext/jni/src/org/sqlite/jni/Fts5Function.java 65cde7151e441fee012250a5e03277de7babcd11a0c308a832b7940574259bcc F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 9c5d901cce4f7e57c3d623f4e2476f9f79a8eed6e51b2a603f37866018e040ee -F ext/jni/src/org/sqlite/jni/OutputPointer.java c7868f1f4ad63435ee44d409377df7dd7e02592a3734df8887a22a9f74b12751 +F ext/jni/src/org/sqlite/jni/OutputPointer.java d37636dd3b82097792dae9c8c255b135153845407cdbc6689f15c475850d6c93 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 @@ -2076,8 +2076,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 b7a8428fcd969e7a29a23c2dae61883f69501094f2de0f79bbee3c02c672cbf5 -R 59dc3fb86d2e5c0f507a4fc5e8173e50 +P 63e7bbe3d5fcfb531f9d7fa88398c1191570e69b5d11adcb9c5e64b8345b4e6c +R c11e6bcae8d215f11cf9225821fd3c49 U stephan -Z e13f8a71cd8f22ed593837a52fb2f248 +Z 8cab7db6e5db86ab7543a142f8069f36 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0d6ae2989a..5a30673df8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -63e7bbe3d5fcfb531f9d7fa88398c1191570e69b5d11adcb9c5e64b8345b4e6c \ No newline at end of file +1a246fd21657f5bb13eeacc4059894ab787ea9a3c45bd9bdd3030a66643d2fef \ No newline at end of file