From becf29a36c891985ac625a73c164d68718e877c2 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 7 Aug 2023 10:01:59 +0000 Subject: [PATCH] JNI API renaming to better match the C API. FossilOrigin-Name: 6e0bd03d0ba9ee8422853241ba1c4e963d158d1f042855c0cb0026701907896e --- ext/jni/src/c/sqlite3-jni.c | 69 +++++++++++----------- ext/jni/src/c/sqlite3-jni.h | 8 +-- ext/jni/src/org/sqlite/jni/SQLite3Jni.java | 22 +++---- ext/jni/src/org/sqlite/jni/Tester1.java | 10 ++-- manifest | 18 +++--- manifest.uuid | 2 +- 6 files changed, 62 insertions(+), 67 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 71e0ab8cf1..ae89c862a9 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -599,6 +599,18 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj, jclass klazz){ } } +/** + Creates a new jByteArray of length nP, copies p's contents into it, and + returns that byte array. + */ +static jbyteArray s3jni_new_jbyteArray(JNIEnv * const env, const unsigned char * const p, int nP){ + jbyteArray jba = (*env)->NewByteArray(env, (jint)nP); + if(jba){ + (*env)->SetByteArrayRegion(env, jba, 0, (jint)nP, (const jbyte*)p); + } + return jba; +} + /** Uses the java.lang.String(byte[],Charset) constructor to create a new String from UTF-8 string z. n is the number of bytes to @@ -623,9 +635,8 @@ static jstring s3jni_utf8_to_jstring(JNIEnvCache * const jc, }else if( z ){ jbyteArray jba; if( n<0 ) n = sqlite3Strlen30(z); - jba = (*env)->NewByteArray(env, (jsize)n); + jba = s3jni_new_jbyteArray(env, (unsigned const char *)z, (jsize)n); if( jba ){ - (*env)->SetByteArrayRegion(env, jba, 0, n, (jbyte const *)z); rv = (*env)->NewObject(env, jc->g.cString, jc->g.ctorStringBA, jba, jc->g.oCharsetUtf8); UNREF_L(jba); @@ -676,6 +687,19 @@ static char * s3jni_jstring_to_utf8(JNIEnvCache * const jc, return rv; } +/** + Expects to be passed a pointer from sqlite3_column_text16() or + sqlite3_value_text16() and a byte-length value from + sqlite3_column_bytes16() or sqlite3_value_bytes16(). It creates a + Java String of exactly half that character length, returning NULL + if !p or (*env)->NewString() fails. +*/ +static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p, int nP){ + return p + ? (*env)->NewString(env, (const jchar *)p, (jsize)(nP/2)) + : NULL; +} + /** Fetches the S3Global.envCache row for the given env, allocing a row if needed. When a row is allocated, its state is initialized @@ -2141,47 +2165,22 @@ JDECL(jlong,1column_1int64)(JENV_CSELF, jobject jpStmt, return (jlong)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx); } -/** - Expects to be passed a pointer from sqlite3_column_text16() or - sqlite3_value_text16() and a length value from - sqlite3_column_bytes16() or sqlite3_value_bytes16(). It creates a - Java String of exactly half that length, returning NULL if !p or - (*env)->NewString() fails. -*/ -static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p, int nP){ - return p - ? (*env)->NewString(env, (const jchar *)p, (jsize)(nP/2)) - : NULL; -} - -/** - Creates a new jByteArray of length nP, copies p's contents into it, and - returns that byte array. - */ -static jbyteArray s3jni_new_jbyteArray(JNIEnv * const env, const unsigned char * const p, int nP){ - jbyteArray jba = (*env)->NewByteArray(env, (jint)nP); - if(jba){ - (*env)->SetByteArrayRegion(env, jba, 0, (jint)nP, (const jbyte*)p); - } - return jba; +JDECL(jbyteArray,1column_1text)(JENV_CSELF, jobject jpStmt, + jint ndx){ + sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt); + const int n = sqlite3_column_bytes(stmt, (int)ndx); + const unsigned char * const p = sqlite3_column_text(stmt, (int)ndx); + return s3jni_new_jbyteArray(env, p, n); } -JDECL(jstring,1column_1text)(JENV_CSELF, jobject jpStmt, - jint ndx){ +JDECL(jstring,1column_1text16)(JENV_CSELF, jobject jpStmt, + jint ndx){ sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt); const int n = sqlite3_column_bytes16(stmt, (int)ndx); const void * const p = sqlite3_column_text16(stmt, (int)ndx); return s3jni_text16_to_jstring(env, p, n); } -JDECL(jbyteArray,1column_1text_1utf8)(JENV_CSELF, jobject jpStmt, - jint ndx){ - sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt); - const int n = sqlite3_column_bytes(stmt, (int)ndx); - const unsigned char * const p = sqlite3_column_text(stmt, (int)ndx); - return s3jni_new_jbyteArray(env, p, n); -} - JDECL(jobject,1column_1value)(JENV_CSELF, jobject jpStmt, jint ndx){ sqlite3_value * const sv = sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx); diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 01bf381ae0..a8a79df890 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1013,18 +1013,18 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1table_ /* * Class: org_sqlite_jni_SQLite3Jni - * Method: sqlite3_column_text + * Method: sqlite3_column_text16 * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text +JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text16 (JNIEnv *, jclass, jobject, jint); /* * Class: org_sqlite_jni_SQLite3Jni - * Method: sqlite3_column_text_utf8 + * Method: sqlite3_column_text * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)[B */ -JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text_1utf8 +JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text (JNIEnv *, jclass, jobject, jint); /* diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index 6a72dd8739..b3e435fa90 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -326,25 +326,18 @@ public final class SQLite3Jni { public static native String sqlite3_column_table_name(@NotNull sqlite3_stmt stmt, int ndx); /** - Because Java strings use UTF-16 and JNI speaks Modified UTF-8 - instead of standard UTF8[^1], this routine functions equivalently to - the native sqlite3_column_text16(), so requires conversion from - the db if the db uses the default encoding of UTF-8. - - To extract _standard_ UTF-8, use sqlite3_column_text_utf8(). + To extract _standard_ UTF-8, use sqlite3_column_text(). This API includes no functions for working with Java's Modified UTF-8. - - [^1]: https://stackoverflow.com/questions/7921016 */ - public static native String sqlite3_column_text(@NotNull sqlite3_stmt stmt, int ndx); + public static native String sqlite3_column_text16(@NotNull sqlite3_stmt stmt, int ndx); /** - Similar to sqlite3_column_text(), but the result is an array encoded - in standard UTF-8, not Modified UTF-8. + Returns the given column's contents as UTF-8-encoded (not MUTF-8) text. + Use sqlite3_column_text16() to fetch the text */ - public static native byte[] sqlite3_column_text_utf8(@NotNull sqlite3_stmt stmt, - int ndx); + public static native byte[] sqlite3_column_text(@NotNull sqlite3_stmt stmt, + int ndx); // The real utility of this function is questionable. // /** @@ -455,6 +448,9 @@ public final class SQLite3Jni { public static native String sqlite3_errstr(int resultCode); + /** + Note that the offset values assume UTF-8-encoded SQL. + */ public static native int sqlite3_error_offset(@NotNull sqlite3 db); public static native int sqlite3_finalize(@NotNull sqlite3_stmt stmt); diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index b6058d0c77..b255910614 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -331,7 +331,7 @@ public class Tester1 { StringBuilder sbuf = new StringBuilder(); int n = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ - String txt = sqlite3_column_text(stmt, 0); + String txt = sqlite3_column_text16(stmt, 0); //outln("txt = "+txt); sbuf.append( txt ); ++n; @@ -412,7 +412,7 @@ public class Tester1 { sqlite3_stmt stmt = prepare(db, "SELECT a FROM t ORDER BY a COLLATE reversi"); int counter = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ - final String val = sqlite3_column_text(stmt, 0); + final String val = sqlite3_column_text16(stmt, 0); ++counter; //outln("REVERSI'd row#"+counter+": "+val); switch(counter){ @@ -426,7 +426,7 @@ public class Tester1 { stmt = prepare(db, "SELECT a FROM t ORDER BY a"); counter = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ - final String val = sqlite3_column_text(stmt, 0); + final String val = sqlite3_column_text16(stmt, 0); ++counter; //outln("Non-REVERSI'd row#"+counter+": "+val); switch(counter){ @@ -634,7 +634,7 @@ public class Tester1 { affirm( 0 == rc ); int n = 0; while( SQLITE_ROW == sqlite3_step(stmt) ){ - final String s = sqlite3_column_text(stmt, 0); + final String s = sqlite3_column_text16(stmt, 0); final int i = sqlite3_column_int(stmt, 1); switch(++n){ case 1: affirm( "a".equals(s) && 9==i ); break; @@ -710,7 +710,7 @@ public class Tester1 { case SQLITE_TRACE_ROW: affirm(pNative instanceof sqlite3_stmt); affirm(null == x); - //outln("TRACE_ROW = "+sqlite3_column_text((sqlite3_stmt)pNative, 0)); + //outln("TRACE_ROW = "+sqlite3_column_text16((sqlite3_stmt)pNative, 0)); break; case SQLITE_TRACE_CLOSE: affirm(pNative instanceof sqlite3); diff --git a/manifest b/manifest index ef5812c8c5..853b14685d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssqlite3_stmt()\sJava\sctor\sprivate\s-\sit's\sonly\sconstructed\sfrom\sJNI\scode. -D 2023-08-07T01:06:27.645 +C JNI\sAPI\srenaming\sto\sbetter\smatch\sthe\sC\sAPI. +D 2023-08-07T10:01:59.163 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,8 +232,8 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99 F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d -F ext/jni/src/c/sqlite3-jni.c a59464adb77c0d2c539483b4d09b8c547dc97c73cf7f26b4934602c8cd4da28d -F ext/jni/src/c/sqlite3-jni.h 68d219dd351676e819deb38926ebcee0fda141403ce4efa60c3d8bd77993d220 +F ext/jni/src/c/sqlite3-jni.c e24884ce42955da0effd14c5dacf072cecaf2f10471f83384f43c0ba4ed94805 +F ext/jni/src/c/sqlite3-jni.h c39e30a8e06e93f7b84e3733202f24a75fce16875f3b2f1b89ae28e38e3dfcbb F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 F ext/jni/src/org/sqlite/jni/AutoExtension.java 3409ad8954d6466bf772e6be9379e0e337312b446b668287062845755a16844d F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c @@ -251,8 +251,8 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java ebdd33d48064c3302d0d4a6dd345562a 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 e43d17ef7601d6294fa5ba7e15a2be2bcb819b41f4fe0ac069ce45e324b5a928 -F ext/jni/src/org/sqlite/jni/Tester1.java 762c866e3c401f8de2551e8bdc5252f5943693fe6bbbace82c3af984c190a0fd +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 7f15c3d17d61c19d51dfa32d810707eaa8c9149c05a364ad01fba6c2a6bda6f7 +F ext/jni/src/org/sqlite/jni/Tester1.java 55bf9c35c4a5649bdfb6ce940117d33ec24a6722bc252fadf7bc7102b9e94d6a F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d @@ -2083,8 +2083,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 fa0a6b6e8e6c711585bca30357e465f7a2f08a1c7159ecf23031af1e5158b89d -R 1b41c977473ab5e66f03fccf5b662909 +P ce82c42f151e38b23945e6f5dd99cb6a77b3c6440508f41abc35e9f6c29cd440 +R 7eccdfc2ef7173451e58d94e7f4df988 U stephan -Z ce9a2d4985cae8c45da2163e3000eab1 +Z da2d66afb2e1f6b314be079f14f3192a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e9dfa5ab7e..507b2c53f0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ce82c42f151e38b23945e6f5dd99cb6a77b3c6440508f41abc35e9f6c29cd440 \ No newline at end of file +6e0bd03d0ba9ee8422853241ba1c4e963d158d1f042855c0cb0026701907896e \ No newline at end of file -- 2.47.2