SQLite Forum

JNI build error
Login

JNI build error

(1) By anonymous on 2023-11-06 18:49:46 [link] [source]

Hello, After downloading https://sqlite.org/2023/sqlite-src-3440000.zip,

$ export JDK_HOME=/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home/
$ ./configure "CFLAGS=-DSQLITE_ENABLE_COLUMN_METADATA"
$ cd ext/jni
$ make
...
cc -std=c99 -fPIC -I. -I../../ -I./src/c -I/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home//include -I/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home//include/darwin -I/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home//include/ir.idl -I/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home//include/orb.idl -Wall -DSQLITE_JNI_ENABLE_SQLTester -DSQLITE_THREADSAFE=1 -DSQLITE_TEMP_STORE=2 -DSQLITE_USE_URI=1 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_C=../../sqlite3.c -DSQLITE_JNI_FATAL_OOM=1 -DSQLITE_JNI_ENABLE_METRICS=1 -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_BYTECODE_VTAB -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_ENABLE_PREUPDATE_HOOK -DSQLITE_ENABLE_NORMALIZE -DSQLITE_ENABLE_SQLLOG -DSQLITE_DEBUG -g -DDEBUG -UNDEBUG -DSQLITE_ENABLE_FTS5 \
			./src/c/sqlite3-jni.c -shared -o bld/libsqlite3-jni.so
Undefined symbols for architecture x86_64:
  "_sqlite3_column_database_name", referenced from:
      _Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name in sqlite3-jni-038deb.o
  "_sqlite3_column_origin_name", referenced from:
      _Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1origin_1name in sqlite3-jni-038deb.o
  "_sqlite3_column_table_name", referenced from:
      _Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1table_1name in sqlite3-jni-038deb.o
ld: symbol(s) not found for architecture x86_64

What should I do ?

Thanks.

(2) By Stephan Beal (stephan) on 2023-11-06 21:47:51 in reply to 1 [link] [source]

What should I do ?

The CFLAGS you've passed to configure have no effect on the jni build, but that flag is apparently necessary for the missing functions it's complaining about. All of its flags come from ext/jni/GNUmakefile.

What i don't understand is why the dev build works without that flag yet it includes those functions.

The quick fix for you is to modify ext/jni/GNUmakefile to add that flag:

$ fossil diff
Index: ext/jni/GNUmakefile
==================================================================
--- ext/jni/GNUmakefile
+++ ext/jni/GNUmakefile
@@ -225,11 +225,12 @@
   -DSQLITE_ENABLE_DBSTAT_VTAB \
   -DSQLITE_ENABLE_BYTECODE_VTAB \
   -DSQLITE_ENABLE_OFFSET_SQL_FUNC \
   -DSQLITE_ENABLE_PREUPDATE_HOOK \
   -DSQLITE_ENABLE_NORMALIZE \
-  -DSQLITE_ENABLE_SQLLOG
+  -DSQLITE_ENABLE_SQLLOG \
+  -DSQLITE_ENABLE_COLUMN_METADATA
 endif
 
 ifeq (1,$(opt.debug))
   SQLITE_OPT += -DSQLITE_DEBUG -g -DDEBUG -UNDEBUG
 else

That should fix that particular problem for you. It will be added to the trunk momentarily but why it works on my systems without that flag is a mystery.

(3) By Stephan Beal (stephan) on 2023-11-06 21:58:22 in reply to 2 [link] [source]

... why it works on my systems without that flag is a mystery.

Mystery solved: on my system it does not trigger an error for those because they're not actually used anywhere. Test code has now been added which makes use of those functions, which will cause the build to fail if that build flag isn't used.

That fix is now in the trunk.

(4) By anonymous on 2023-11-07 17:35:26 in reply to 2 [link] [source]

Thanks. Just to confirm that the above patch fixes the issue on MacOS:

$ size bld/libsqlite3-jni.so
__TEXT	__DATA	__OBJC	others	dec	hex
2080768	32768	0	540672	2654208	288000
$ otool -L bld/libsqlite3-jni.so
bld/libsqlite3-jni.so:
	bld/libsqlite3-jni.so (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)

But on Windows / Mingw64:

./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1co
mplete'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, struct _jobject *
'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:3031:1: note: in expansion of macro 'S3JniApi'
3031 | S3JniApi(sqlite3_complete(),int,1complete)(
      | ^~~~~~~~
In file included from ./src/c/sqlite3-jni.c:155:
./src/c/sqlite3-jni.h:1223:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1complete' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *
)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *)'}
1223 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1db
_1release_1memory'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, struct
_jobject *)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
     |                                           ^~~~~~~
./src/c/sqlite3-jni.c:3478:1: note: in expansion of macro 'S3JniApi'
3478 | S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1335:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1db_1release_1memory' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct
_jobject *)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject
*)'}
1335 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1release_1memory
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1re
sult_1error'; have 'void(const struct JNINativeInterface_ ** const,  struct _jobject *, struct _jobj
ect *, struct _jobject *, int)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4288:1: note: in expansion of macro 'S3JniApi'
4288 | S3JniApi(sqlite3_result_error(),void,1result_1error)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1655:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1result_1error' with type 'void(const struct JNINativeInterface_ **, struct _jobject *, struct _jobj
ect *, struct _jobject *, jint)' {aka 'void(const struct JNINativeInterface_ **, struct _jobject *,
struct _jobject *, struct _jobject *, long int)'}
1655 | JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1ta
ble_1column_1metadata'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, str
uct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _
jobject *, struct _jobject *, struct _jobject *, struct _jobject *)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4642:1: note: in expansion of macro 'S3JniApi'
4642 | S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1927:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1table_1column_1metadata' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, st
ruct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct
_jobject *, struct _jobject *, struct _jobject *, struct _jobject *)' {aka 'long int(const struct JN
INativeInterface_ **, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, st
ruct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct
_jobject *)'}
1927 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1table_1column_1metadata
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1va
lue_1bytes'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, jlong)' {aka
int(const struct JNINativeInterface_ ** const,  struct _jobject *, long long int)'}
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4828:1: note: in expansion of macro 'S3JniApi'
4828 | S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1991:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1value_1bytes' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {aka
'long int(const struct JNINativeInterface_ **, struct _jobject *, long long int)'}
1991 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1bytes
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1va
lue_1bytes16'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, jlong)' {aka
'int(const struct JNINativeInterface_ ** const,  struct _jobject *, long long int)'}
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4835:1: note: in expansion of macro 'S3JniApi'
4835 | S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1999:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1value_1bytes16' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {ak
a 'long int(const struct JNINativeInterface_ **, struct _jobject *, long long int)'}
1999 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1bytes16
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5005:3: error: conflicting types for 'Java_org_sqlite_jni_fts5_Fts5ExtensionAp
i_xSetAuxdata'; have 'int(const struct JNINativeInterface_ ** const,  struct _jobject *, struct _job
ject *, struct _jobject *)'
5005 |   Java_org_sqlite_jni_fts5_Fts5ExtensionApi_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5013:3: note: in expansion of macro 'JniFuncNameFtsXA'
5013 |   JniFuncNameFtsXA(Suffix)
      |   ^~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5502:1: note: in expansion of macro 'JniDeclFtsXA'
5502 | JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
      | ^~~~~~~~~~~~
./src/c/sqlite3-jni.h:2305:24: note: previous declaration of 'Java_org_sqlite_jni_fts5_Fts5Extension
Api_xSetAuxdata' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct _job
ject *, struct _jobject *)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, s
truct _jobject *, struct _jobject *)'}
2305 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_fts5_Fts5ExtensionApi_xSetAuxdata
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [GNUmakefile:305: bld/libsqlite3-jni.so] Error 1

Regards.

(5.1) By Stephan Beal (stephan) on 2023-11-07 19:59:20 edited from 5.0 in reply to 4 [link] [source]

Thanks. Just to confirm that the above patch fixes the issue on MacOS:

Thank you!

But on Windows / Mingw64:

Frankly, that's the compiler being buggy (or, at a minimum, overly-finicky). Can you confirm whether this patch works around that?

$ fossil diff
Index: ext/jni/src/c/sqlite3-jni.c
==================================================================
--- ext/jni/src/c/sqlite3-jni.c
+++ ext/jni/src/c/sqlite3-jni.c
@@ -199,12 +199,12 @@
 ** only rarely needed in this code), but to be pedantically correct we
 ** need the proper type in the signature.
 **
 ** https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers
 */
-#define JniArgsEnvObj JNIEnv * const env, jobject jSelf
-#define JniArgsEnvClass JNIEnv * const env, jclass jKlazz
+#define JniArgsEnvObj JNIEnv * env, jobject jSelf
+#define JniArgsEnvClass JNIEnv * env, jclass jKlazz
 /*
 ** Helpers to account for -Xcheck:jni warnings about not having
 ** checked for exceptions.
 */
 #define S3JniIfThrew if( (*env)->ExceptionCheck(env) )

(6) By anonymous on 2023-11-08 06:26:19 in reply to 5.1 [link] [source]

Now (after applying above patch), the compiler complains about jint (long int) vs int:

./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1co
mplete'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:3031:1: note: in expansion of macro 'S3JniApi'
 3031 | S3JniApi(sqlite3_complete(),int,1complete)(
      | ^~~~~~~~
In file included from ./src/c/sqlite3-jni.c:155:
./src/c/sqlite3-jni.h:1223:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1complete' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *
)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *)'}
 1223 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1db
_1release_1memory'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobjec
t *)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:3478:1: note: in expansion of macro 'S3JniApi'
 3478 | S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1335:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1db_1release_1memory' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct
 _jobject *)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject
 *)'}
 1335 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1release_1memory
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1re
sult_1error'; have 'void(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *,
struct _jobject *, int)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4288:1: note: in expansion of macro 'S3JniApi'
 4288 | S3JniApi(sqlite3_result_error(),void,1result_1error)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1655:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1result_1error' with type 'void(const struct JNINativeInterface_ **, struct _jobject *, struct _jobj
ect *, struct _jobject *, jint)' {aka 'void(const struct JNINativeInterface_ **, struct _jobject *,
struct _jobject *, struct _jobject *, long int)'}
 1655 | JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1ta
ble_1column_1metadata'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, struct _jo
bject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject
 *, struct _jobject *, struct _jobject *, struct _jobject *)'
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4642:1: note: in expansion of macro 'S3JniApi'
 4642 | S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1927:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1table_1column_1metadata' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, st
ruct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct
_jobject *, struct _jobject *, struct _jobject *, struct _jobject *)' {aka 'long int(const struct JN
INativeInterface_ **, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, st
ruct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct _jobject *, struct
_jobject *)'}
 1927 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1table_1column_1metadata
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1va
lue_1bytes'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {aka 'int(con
st struct JNINativeInterface_ **, struct _jobject *, long long int)'}
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4828:1: note: in expansion of macro 'S3JniApi'
 4828 | S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1991:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1value_1bytes' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {aka
'long int(const struct JNINativeInterface_ **, struct _jobject *, long long int)'}
 1991 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1bytes
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:172:3: error: conflicting types for 'Java_org_sqlite_jni_capi_CApi_sqlite3_1va
lue_1bytes16'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {aka 'int(c
onst struct JNINativeInterface_ **, struct _jobject *, long long int)'}
  172 |   Java_org_sqlite_jni_capi_CApi_sqlite3_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:176:32: note: in expansion of macro 'JniFuncName'
  176 |   JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
      |                                ^~~~~~~~~~~
./src/c/sqlite3-jni.c:184:43: note: in expansion of macro 'JniDecl'
  184 | #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
      |                                           ^~~~~~~
./src/c/sqlite3-jni.c:4835:1: note: in expansion of macro 'S3JniApi'
 4835 | S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)(
      | ^~~~~~~~
./src/c/sqlite3-jni.h:1999:24: note: previous declaration of 'Java_org_sqlite_jni_capi_CApi_sqlite3_
1value_1bytes16' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, jlong)' {ak
a 'long int(const struct JNINativeInterface_ **, struct _jobject *, long long int)'}
 1999 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1bytes16
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5005:3: error: conflicting types for 'Java_org_sqlite_jni_fts5_Fts5ExtensionAp
i_xSetAuxdata'; have 'int(const struct JNINativeInterface_ **, struct _jobject *, struct _jobject *,
 struct _jobject *)'
 5005 |   Java_org_sqlite_jni_fts5_Fts5ExtensionApi_ ## Suffix
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5013:3: note: in expansion of macro 'JniFuncNameFtsXA'
 5013 |   JniFuncNameFtsXA(Suffix)
      |   ^~~~~~~~~~~~~~~~
./src/c/sqlite3-jni.c:5502:1: note: in expansion of macro 'JniDeclFtsXA'
 5502 | JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
      | ^~~~~~~~~~~~
./src/c/sqlite3-jni.h:2305:24: note: previous declaration of 'Java_org_sqlite_jni_fts5_Fts5Extension
Api_xSetAuxdata' with type 'jint(const struct JNINativeInterface_ **, struct _jobject *, struct _job
ject *, struct _jobject *)' {aka 'long int(const struct JNINativeInterface_ **, struct _jobject *, s
truct _jobject *, struct _jobject *)'}
 2305 | JNIEXPORT jint JNICALL Java_org_sqlite_jni_fts5_Fts5ExtensionApi_xSetAuxdata
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [GNUmakefile:305: bld/libsqlite3-jni.so] Error 1

(7) By Stephan Beal (stephan) on 2023-11-08 12:46:24 in reply to 6 [link] [source]

Now (after applying above patch), the compiler complains about jint (long int) vs int:

Thank you for that. i will take a look at these over the next few days. On the platforms tested so far, jint and int are the same type.

(8) By Stephan Beal (stephan) on 2023-11-08 13:00:17 in reply to 7 [link] [source]

i will take a look at these over the next few days. On the platforms tested so far, jint and int are the same type.

That went more quickly than the verbosity of the compilation errors implied it would. The trunk now has those fixes and on that page, at the top of the "Changes" section, is a link labeled "Patch" where you can download a patch (if you're working from those).

Thank you again for the reports!

(9) By anonymous on 2023-11-08 17:13:48 in reply to 8 [link] [source]

Thank you for your fixes.

I will try to keep you posting if I find some other quirks.

(And don't worry, no hurry, I am just playing with your API).

(10) By Stephan Beal (stephan) on 2023-11-08 18:14:05 in reply to 9 [link] [source]

I will try to keep you posting if I find some other quirks.

Please do - my platforms are some flavor of Linux, so lack a great deal of diversity.

(And don't worry, no hurry, I am just playing with your API).

Just FYI: the low-level/C-style one is really the core and is what we intend to support and maintain long-term once it's finalized. The higher-level wrapper is based primarily on input from Java-centric developers and is intended to provide "one potential solution" to the problem of providing a high-level wrapper. It is most certainly not intended be "the" solution to that problem. It's our hope that the community will create any number of higher-level wrappers to suit their specific needs and preferences.

(11) By anonymous on 2023-11-09 07:28:39 in reply to 10 [source]

Ok,

The Windows build with mingw64 works with these changes:

  • In GNUmakefile, I need to force the encoding
javac.flags ?= -Xlint:unchecked -Xlint:deprecation -encoding utf8
  • And in ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java (trunk version), I need to do this:
    CApi.sqlite3_blob_close(this/*.clearNativePointer()*/);

So all errors reletated to jint are fixed.

Thanks.

(12) By Stephan Beal (stephan) on 2023-11-09 12:01:46 in reply to 11 [link] [source]

-encoding utf8

Fixed.

CApi.sqlite3_blob_close(this/*.clearNativePointer()*/);

Fixed. That one should have broken on my machine as well but wasn't. Perhaps a stale class file was being used (wouldn't be the first time that's happened).

Thank you again for the feedback and corrections!

(13) By anonymous on 2023-11-09 18:16:40 in reply to 12 [link] [source]

On MacOS, I had to fix the generated dynamic library extension (.so vs .dylib):

mv bld/libsqlite3-jni.{so,dylib}

to run the tests.

But then no error: make test is ok on MacOS.

I will try to use your code as the bottom layer of some SQLite JDBC drivers and, once done, check their tests. (just a try, no promise...)

(14) By Stephan Beal (stephan) on 2023-11-09 19:25:04 in reply to 13 [link] [source]

mv bld/libsqlite3-jni.{so,dylib}

i wouldn't know how to reliably detect "this is Mac" in the makefile, and don't have/use that platform to try it out with, but if you can tell me how, we can change the build to use the dylib extension.

(15) By anonymous on 2023-11-11 10:18:10 in reply to 14 [link] [source]

Sorry for the dylib extension I can't help you.

I am not sure but for me there is a latent bug here:

https://www.sqlite.org/cgi/src/file?name=ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java&ci=trunk

      this.resultColCount = CApi.sqlite3_column_count(stmt);

Because a column may be added or removed with an ALTER TABLE and there is no way to know when a stmt is recompiled.

(17) By Stephan Beal (stephan) on 2023-11-11 11:11:35 in reply to 15 [link] [source]

I am not sure but for me there is a latent bug here

Good catch. "The problem" is that we need that value frequently for validation and it would be expensive to fetch every time we need it. i'll need to investigate another solution for that.

(16) By anonymous on 2023-11-11 10:37:30 in reply to 14 [link] [source]

There is another issue here:

  void const * const p = sqlite3_column_blob(pStmt, (int)ndx);
  int const n = p ? sqlite3_column_bytes(pStmt, (int)ndx) : 0;

  return p ? s3jni_new_jbyteArray(p, n) : 0;

Because sqlite3_column_blob return NULL for a zero-length BLOB. So you need to check if sqlite3_column_type(pStmt, (int)ndx) == SQLITE_NULL to make the distinction between a null value and zero-length byte array.

(18) By Stephan Beal (stephan) on 2023-11-11 11:17:09 in reply to 16 [link] [source]

Because sqlite3_column_blob return NULL for a zero-length BLOB. So you need to check if sqlite3_column_type(pStmt, (int)ndx) == SQLITE_NULL to make the distinction between a null value and zero-length byte array.

Either way, we would return NULL in that case, so that check isn't necessary. We're not going to return a length-zero byte array because that would change the semantics. The only places where we knowingly change semantics in the low-level API are cases where we have to for cross-language compatibility reasons, like callbacks.

(19) By anonymous on 2023-11-11 11:28:35 in reply to 18 [link] [source]

Another issue here:

    final OutputPointer.sqlite3_blob out = new OutputPointer.sqlite3_blob();
    checkRc(
      CApi.sqlite3_blob_open(thisDb(), dbName, tableName, columnName,
                             iRow, writeable ? 1 : 0, out)
    );

See http://sqlite.org/c3ref/blob_open.html

unless the error code is SQLITE_MISUSE, *ppBlob is set to NULL.

So you may need to close the sqlite3_blob on SQLITE_MISUSE.

(20.2) By Stephan Beal (stephan) on 2023-11-11 11:49:15 edited from 20.1 in reply to 19 [link] [source]

So you may need to close the sqlite3_blob on SQLITE_MISUSE.

The complete quote is:

Otherwise an error code is returned and, unless the error code is SQLITE_MISUSE, *ppBlob is set to NULL. This means that, provided the API is not misused, it is always safe to call sqlite3_blob_close() on *ppBlob after this function it returns.

It's pointing out that ppBlob will not be left in its call-time state (very possibly uninitialized, as many C coders do not initialize such output pointers before passing them to their constructors/factories).

It also says:

Unless it returns SQLITE_MISUSE, this function sets the database connection error code and message accessible via sqlite3_errcode() and sqlite3_errmsg() and related functions.

Strongly implying that the blob is not opened on error (like a db handle may be).

In any case, thank you for pointing that out. i'll need to verify the behavior in the sources and potentially update the docs. (Edit: verified: the lib only assigns *ppBlob to non-NULL if the call succeeds.)

Thank you for your continued feedback. My responses may be slowed the rest of the weekend, but all of it is being read and considered.