From 6a19159e9fd8bfd0b995b61511444b4a71e9f3bb Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Wed, 25 Nov 2020 17:30:36 +0000 Subject: [PATCH 1/5] feat: add a complex type for the SQL handle The previous approach was using a simple type to return the SQL handle. The returned handle value was a mix between the result value of SQLite operation and the SQL handle, where negative number indicates an error, causing the issues in the recent devices running Android 11, where the memory addresses of the handle were valid but they were also negative numbers when converted to the `long long` type. With this new complex type for the SQL Handle, we are now able to return both the result of the SQLite operation and the SQL handle. References https://outsystemsrd.atlassian.net/browse/RNMT-4515 --- native/sqlc.c | 33 +++++++++++++++++++++++---------- native/sqlc.h | 12 +++++++++--- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/native/sqlc.c b/native/sqlc.c index aa5099a..d8b65a3 100644 --- a/native/sqlc.c +++ b/native/sqlc.c @@ -6,8 +6,6 @@ #include "sqlite3.h" -#define BASE_HANDLE_OFFSET 0x100000000LL - #ifdef SQLC_KEEP_ANDROID_LOG // ref: http://www.ibm.com/developerworks/opensource/tutorials/os-androidndk/index.html #define MYLOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "sqlc", __VA_ARGS__) @@ -15,23 +13,29 @@ #define MYLOG(...) ; #endif -#define HANDLE_FROM_VP(p) ( BASE_HANDLE_OFFSET + ( (unsigned char *)(p) - (unsigned char *)NULL ) ) -#define HANDLE_TO_VP(h) (void *)( (unsigned char *)NULL + (ptrdiff_t)((h) - BASE_HANDLE_OFFSET) ) +#define HANDLE_FROM_VP(p) (( (unsigned char *)(p) - (unsigned char *)NULL ) ) +#define HANDLE_TO_VP(h) (void *)( (unsigned char *)NULL + (ptrdiff_t)((h)) ) int sqlc_api_version_check(int sqlc_api_version) { return (sqlc_api_version != SQLC_API_VERSION) ? SQLC_RESULT_ERROR : SQLC_RESULT_OK; } -sqlc_handle_t sqlc_api_db_open(int sqlc_api_version, const char *filename, int flags) +sqlc_handle_ct* sqlc_api_db_open(int sqlc_api_version, const char *filename, int flags) { - if (sqlc_api_version != SQLC_API_VERSION) return SQLC_RESULT_ERROR; + if (sqlc_api_version != SQLC_API_VERSION) { + sqlc_handle_ct* resp = malloc(sizeof(sqlc_handle_ct)); + resp->result = SQLC_RESULT_ERROR; + resp->handle = 0; + return resp; + } return sqlc_db_open(filename, flags); } -sqlc_handle_t sqlc_db_open(const char *filename, int flags) +sqlc_handle_ct* sqlc_db_open(const char *filename, int flags) { + sqlc_handle_ct *resp; sqlite3 *d1; int r1; @@ -41,11 +45,16 @@ sqlc_handle_t sqlc_db_open(const char *filename, int flags) MYLOG("db_open %s result %d ptr %p", filename, r1, d1); - return (r1 == 0) ? HANDLE_FROM_VP(d1) : -r1; + resp = malloc (sizeof (sqlc_handle_ct)); + resp->result = (r1 == 0) ? 0 : -r1; + resp->handle = HANDLE_FROM_VP(d1); + + return resp; } -sqlc_handle_t sqlc_db_prepare_st(sqlc_handle_t db, const char *sql) +sqlc_handle_ct* sqlc_db_prepare_st(sqlc_handle_t db, const char *sql) { + sqlc_handle_ct *resp; sqlite3 *mydb = HANDLE_TO_VP(db); sqlite3_stmt *s; int rv; @@ -54,7 +63,11 @@ sqlc_handle_t sqlc_db_prepare_st(sqlc_handle_t db, const char *sql) rv = sqlite3_prepare_v2(mydb, sql, -1, &s, NULL); - return (rv == 0) ? HANDLE_FROM_VP(s) : -rv; + resp = malloc (sizeof (sqlc_handle_ct)); + resp->result = (rv == 0) ? 0 : -rv; + resp->handle = HANDLE_FROM_VP(s); + + return resp; } /** FUTURE TBD (???) for sqlcipher: diff --git a/native/sqlc.h b/native/sqlc.h index 2cf47ce..9f58136 100644 --- a/native/sqlc.h +++ b/native/sqlc.h @@ -39,14 +39,20 @@ typedef long long sqlc_long_t; /* negative number indicates an error: */ typedef sqlc_long_t sqlc_handle_t; +#pragma once +typedef struct { + int result; + sqlc_handle_t handle; +}sqlc_handle_ct; + /* RECOMMENDED (alt 1): Use this call at startup to check Java/native library match * (returns SQLC_RESULT_OK [0] if OK, other value in case of mismatch) */ int sqlc_api_version_check(int sqlc_api_version); /* RECOMMENDED (alt 2): Check Java/native library match and open database handle */ -sqlc_handle_t sqlc_api_db_open(int sqlc_api_version, const char *filename, int flags); +sqlc_handle_ct* sqlc_api_db_open(int sqlc_api_version, const char *filename, int flags); -sqlc_handle_t sqlc_db_open(const char *filename, int flags); +sqlc_handle_ct* sqlc_db_open(const char *filename, int flags); // FUTURE TBD (???): //sqlc_handle_t sqlc_db_open_vfs(const char *filename, int flags, const char *vfs); @@ -59,7 +65,7 @@ int sqlc_db_key_native_string(sqlc_handle_t db, char *key_string); // FUTURE TBD (???) for sqlcipher: // int sqlc_db_rekey_string_native(sqlc_handle_t db, char *key_string); -sqlc_handle_t sqlc_db_prepare_st(sqlc_handle_t db, const char *sql); +sqlc_handle_ct* sqlc_db_prepare_st(sqlc_handle_t db, const char *sql); sqlc_long_t sqlc_db_last_insert_rowid(sqlc_handle_t db); int sqlc_db_total_changes(sqlc_handle_t db); From 5d4f4a5ed77494b0e41c013b2f8a6490766ff264 Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Wed, 25 Nov 2020 17:30:59 +0000 Subject: [PATCH 2/5] feat: add a java class to match the complex type for the SQL handle References https://outsystemsrd.atlassian.net/browse/RNMT-4515 --- java/io/liteglue/SQLiteNative.java | 4 ++-- java/io/liteglue/SQLiteResponse.java | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 java/io/liteglue/SQLiteResponse.java diff --git a/java/io/liteglue/SQLiteNative.java b/java/io/liteglue/SQLiteNative.java index 2a179f9..0f164f2 100644 --- a/java/io/liteglue/SQLiteNative.java +++ b/java/io/liteglue/SQLiteNative.java @@ -57,10 +57,10 @@ public class SQLiteNative { public static native long sqlc_db_last_insert_rowid(long db); /** Interface to C language function:
sqlc_handle_t sqlc_db_open(const char * filename, int flags); */ - public static native long sqlc_db_open(String filename, int flags); + public static native SQLiteResponse sqlc_db_open(String filename, int flags); /** Interface to C language function:
sqlc_handle_t sqlc_db_prepare_st(sqlc_handle_t db, const char * sql); */ - public static native long sqlc_db_prepare_st(long db, String sql); + public static native SQLiteResponse sqlc_db_prepare_st(long db, String sql); /** Interface to C language function:
int sqlc_db_total_changes(sqlc_handle_t db); */ public static native int sqlc_db_total_changes(long db); diff --git a/java/io/liteglue/SQLiteResponse.java b/java/io/liteglue/SQLiteResponse.java new file mode 100644 index 0000000..cc6b9d4 --- /dev/null +++ b/java/io/liteglue/SQLiteResponse.java @@ -0,0 +1,20 @@ +package io.liteglue; + +public class SQLiteResponse { + private int result; + private long handle; + + public SQLiteResponse(int result, long handle) { + this.result = result; + this.handle = handle; + } + + public int getResult() { + return this.result; + } + + public long getHandle() { + return this.handle; + } + +} \ No newline at end of file From a69fa8fea29d77b781b1250554932174328ff337 Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Wed, 25 Nov 2020 17:32:32 +0000 Subject: [PATCH 3/5] feat: update JNI to use the complex type for the SQL handle References https://outsystemsrd.atlassian.net/browse/RNMT-4515 --- native/SQLiteNative_JNI.c | 51 +++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/native/SQLiteNative_JNI.c b/native/SQLiteNative_JNI.c index a266ffe..32f6ca0 100644 --- a/native/SQLiteNative_JNI.c +++ b/native/SQLiteNative_JNI.c @@ -8,13 +8,13 @@ /* Java->C glue code: * Java package: io.liteglue.SQLiteNative - * Java method: long sqlc_api_db_open(int sqlc_api_version, java.lang.String filename, int flags) - * C function: sqlc_handle_t sqlc_api_db_open(int sqlc_api_version, const char * filename, int flags); + * Java method: SQLiteResponse sqlc_api_db_open(int sqlc_api_version, java.lang.String filename, int flags) + * C function: sqlc_handle_ct* sqlc_api_db_open(int sqlc_api_version, const char * filename, int flags); */ -JNIEXPORT jlong JNICALL +JNIEXPORT jobject JNICALL Java_io_liteglue_SQLiteNative_sqlc_1api_1db_1open__ILjava_lang_String_2I(JNIEnv *env, jclass _unused, jint sqlc_api_version, jstring filename, jint flags) { const char* _strchars_filename = NULL; - sqlc_handle_t _res; + sqlc_handle_ct* _res; if ( NULL != filename ) { _strchars_filename = (*env)->GetStringUTFChars(env, filename, (jboolean*)NULL); if ( NULL == _strchars_filename ) { @@ -27,7 +27,14 @@ Java_io_liteglue_SQLiteNative_sqlc_1api_1db_1open__ILjava_lang_String_2I(JNIEnv if ( NULL != filename ) { (*env)->ReleaseStringUTFChars(env, filename, _strchars_filename); } - return _res; + + jclass class = (*env)->FindClass(env,"io/liteglue/SQLiteResponse"); + jmethodID constructor = (*env)->GetMethodID(env, class, "", "(IJ)V"); + jobject instance = (*env)->NewObject(env, class, constructor, _res->result, _res->handle); + + free(_res); + + return instance; } @@ -124,13 +131,13 @@ Java_io_liteglue_SQLiteNative_sqlc_1db_1last_1insert_1rowid__J(JNIEnv *env, jcla /* Java->C glue code: * Java package: io.liteglue.SQLiteNative - * Java method: long sqlc_db_open(java.lang.String filename, int flags) - * C function: sqlc_handle_t sqlc_db_open(const char * filename, int flags); + * Java method: SQLiteResponse sqlc_db_open(java.lang.String filename, int flags) + * C function: sqlc_handle_ct* sqlc_db_open(const char * filename, int flags); */ -JNIEXPORT jlong JNICALL +JNIEXPORT jobject JNICALL Java_io_liteglue_SQLiteNative_sqlc_1db_1open__Ljava_lang_String_2I(JNIEnv *env, jclass _unused, jstring filename, jint flags) { const char* _strchars_filename = NULL; - sqlc_handle_t _res; + sqlc_handle_ct* _res; if ( NULL != filename ) { _strchars_filename = (*env)->GetStringUTFChars(env, filename, (jboolean*)NULL); if ( NULL == _strchars_filename ) { @@ -143,19 +150,26 @@ Java_io_liteglue_SQLiteNative_sqlc_1db_1open__Ljava_lang_String_2I(JNIEnv *env, if ( NULL != filename ) { (*env)->ReleaseStringUTFChars(env, filename, _strchars_filename); } - return _res; + + jclass class = (*env)->FindClass(env,"io/liteglue/SQLiteResponse"); + jmethodID constructor = (*env)->GetMethodID(env, class, "", "(IJ)V"); + jobject instance = (*env)->NewObject(env, class, constructor, _res->result, _res->handle); + + free(_res); + + return instance; } /* Java->C glue code: * Java package: io.liteglue.SQLiteNative - * Java method: long sqlc_db_prepare_st(long db, java.lang.String sql) - * C function: sqlc_handle_t sqlc_db_prepare_st(sqlc_handle_t db, const char * sql); + * Java method: SQLiteResponse sqlc_db_prepare_st(long db, java.lang.String sql) + * C function: sqlc_handle_ct* sqlc_db_prepare_st(sqlc_handle_t db, const char * sql); */ -JNIEXPORT jlong JNICALL +JNIEXPORT jobject JNICALL Java_io_liteglue_SQLiteNative_sqlc_1db_1prepare_1st__JLjava_lang_String_2(JNIEnv *env, jclass _unused, jlong db, jstring sql) { const char* _strchars_sql = NULL; - sqlc_handle_t _res; + sqlc_handle_ct* _res; if ( NULL != sql ) { _strchars_sql = (*env)->GetStringUTFChars(env, sql, (jboolean*)NULL); if ( NULL == _strchars_sql ) { @@ -168,7 +182,14 @@ Java_io_liteglue_SQLiteNative_sqlc_1db_1prepare_1st__JLjava_lang_String_2(JNIEnv if ( NULL != sql ) { (*env)->ReleaseStringUTFChars(env, sql, _strchars_sql); } - return _res; + + jclass class = (*env)->FindClass(env,"io/liteglue/SQLiteResponse"); + jmethodID constructor = (*env)->GetMethodID(env, class, "", "(IJ)V"); + jobject instance = (*env)->NewObject(env, class, constructor, _res->result, _res->handle); + + free(_res); + + return instance; } From e52eca7ade556e146376c75f1349a44466419f4c Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Wed, 25 Nov 2020 17:33:18 +0000 Subject: [PATCH 4/5] chore: update sqlite-amalgamation to version 3.26.0 References https://outsystemsrd.atlassian.net/browse/RNMT-4515 --- sqlite-amalgamation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlite-amalgamation b/sqlite-amalgamation index 295f7c8..ae04d99 160000 --- a/sqlite-amalgamation +++ b/sqlite-amalgamation @@ -1 +1 @@ -Subproject commit 295f7c89b3cdd1575ca8298317535a39a4877264 +Subproject commit ae04d995a77a2682f965731f9abf15a8c089a4d4 From 3cf482d8d4c584cf6cd090c9f3844b6507f9f5e1 Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Wed, 25 Nov 2020 17:35:03 +0000 Subject: [PATCH 5/5] build: update target platform and architectures References https://outsystemsrd.atlassian.net/browse/RNMT-4515 --- jni/Application.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jni/Application.mk b/jni/Application.mk index 64623e9..8d0d6ea 100644 --- a/jni/Application.mk +++ b/jni/Application.mk @@ -1,5 +1,5 @@ #APP_ABI := all -APP_ABI := armeabi armeabi-v7a x86 x86_64 arm64-v8a +APP_ABI := armeabi-v7a x86 x86_64 arm64-v8a # For future consideration (needs testing): #APP_ABI += mips mips64 - +APP_PLATFORM := android-23