diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:07:11 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:07:11 +0000 |
commit | 63847496f14c813a5d80efd5b7de0f1294ffe1e3 (patch) | |
tree | 01c7571c7c762ceee70638549a99834fdd7c411b /ext/jni/README.md | |
parent | Initial commit. (diff) | |
download | sqlite3-63847496f14c813a5d80efd5b7de0f1294ffe1e3.tar.xz sqlite3-63847496f14c813a5d80efd5b7de0f1294ffe1e3.zip |
Adding upstream version 3.45.1.upstream/3.45.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ext/jni/README.md')
-rw-r--r-- | ext/jni/README.md | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/ext/jni/README.md b/ext/jni/README.md new file mode 100644 index 0000000..fc7b5f7 --- /dev/null +++ b/ext/jni/README.md @@ -0,0 +1,316 @@ +SQLite3 via JNI +======================================================================== + +This directory houses a Java Native Interface (JNI) binding for the +sqlite3 API. If you are reading this from the distribution ZIP file, +links to resources in the canonical source tree will note work. The +canonical copy of this file can be browsed at: + + <https://sqlite.org/src/doc/trunk/ext/jni/README.md> + +Technical support is available in the forum: + + <https://sqlite.org/forum> + + +> **FOREWARNING:** this subproject is very much in development and + subject to any number of changes. Please do not rely on any + information about its API until this disclaimer is removed. The JNI + bindings released with version 3.43 are a "tech preview." Once + finalized, strong backward compatibility guarantees will apply. + +Project goals/requirements: + +- A [1-to-1(-ish) mapping of the C API](#1to1ish) to Java via JNI, + insofar as cross-language semantics allow for. A closely-related + goal is that [the C documentation](https://sqlite.org/c3ref/intro.html) + should be usable as-is, insofar as possible, for the JNI binding. + +- Support Java as far back as version 8 (2014). + +- Environment-independent. Should work everywhere both Java + and SQLite3 do. + +- No 3rd-party dependencies beyond the JDK. That includes no + build-level dependencies for specific IDEs and toolchains. We + welcome the addition of build files for arbitrary environments + insofar as they neither interfere with each other nor become + a maintenance burden for the sqlite developers. + +Non-goals: + +- Creation of high-level OO wrapper APIs. Clients are free to create + them off of the C-style API. + +- Virtual tables are unlikely to be supported due to the amount of + glue code needed to fit them into Java. + +- Support for mixed-mode operation, where client code accesses SQLite + both via the Java-side API and the C API via their own native + code. Such cases would be a minefield of potential mis-interactions + between this project's JNI bindings and mixed-mode client code. + + +Hello World +----------------------------------------------------------------------- + +```java +import org.sqlite.jni.*; +import static org.sqlite.jni.CApi.*; + +... + +final sqlite3 db = sqlite3_open(":memory:"); +try { + final int rc = sqlite3_errcode(db); + if( 0 != rc ){ + if( null != db ){ + System.out.print("Error opening db: "+sqlite3_errmsg(db)); + }else{ + System.out.print("Error opening db: rc="+rc); + } + ... handle error ... + } + // ... else use the db ... +}finally{ + // ALWAYS close databases using sqlite3_close() or sqlite3_close_v2() + // when done with them. All of their active statement handles must + // first have been passed to sqlite3_finalize(). + sqlite3_close_v2(db); +} +``` + + +Building +======================================================================== + +The canonical builds assumes a Linux-like environment and requires: + +- GNU Make +- A JDK supporting Java 8 or higher +- A modern C compiler. gcc and clang should both work. + +Put simply: + +```console +$ export JAVA_HOME=/path/to/jdk/root +$ make +$ make test +$ make clean +``` + +The jar distribution can be created with `make jar`, but note that it +does not contain the binary DLL file. A different DLL is needed for +each target platform. + + +<a id='1to1ish'></a> +One-to-One(-ish) Mapping to C +======================================================================== + +This JNI binding aims to provide as close to a 1-to-1 experience with +the C API as cross-language semantics allow. Interface changes are +necessarily made where cross-language semantics do not allow a 1-to-1, +and judiciously made where a 1-to-1 mapping would be unduly cumbersome +to use in Java. In all cases, this binding makes every effort to +provide semantics compatible with the C API documentation even if the +interface to those semantics is slightly different. Any cases which +deviate from those semantics (either removing or adding semantics) are +clearly documented. + +Where it makes sense to do so for usability, Java-side overloads are +provided which accept or return data in alternative forms or provide +sensible default argument values. In all such cases they are thin +proxies around the corresponding C APIs and do not introduce new +semantics. + +In a few cases, Java-specific capabilities have been added in +new APIs, all of which have "_java" somewhere in their names. +Examples include: + +- `sqlite3_result_java_object()` +- `sqlite3_column_java_object()` +- `sqlite3_value_java_object()` + +which, as one might surmise, collectively enable the passing of +arbitrary Java objects from user-defined SQL functions through to the +caller. + + +Golden Rule: Garbage Collection Cannot Free SQLite Resources +------------------------------------------------------------------------ + +It is important that all databases and prepared statement handles get +cleaned up by client code. A database cannot be closed if it has open +statement handles. `sqlite3_close()` fails if the db cannot be closed +whereas `sqlite3_close_v2()` recognizes that case and marks the db as +a "zombie," pending finalization when the library detects that all +pending statements have been closed. Be aware that Java garbage +collection _cannot_ close a database or finalize a prepared statement. +Those things require explicit API calls. + +Classes for which it is sensible support Java's `AutoCloseable` +interface so can be used with try-with-resources constructs. + + +Golden Rule #2: _Never_ Throw from Callbacks (Unless...) +------------------------------------------------------------------------ + +All routines in this API, barring explicitly documented exceptions, +retain C-like semantics. For example, they are not permitted to throw +or propagate exceptions and must return error information (if any) via +result codes or `null`. The only cases where the C-style APIs may +throw is through client-side misuse, e.g. passing in a null where it +may cause a `NullPointerException`. The APIs clearly mark function +parameters which should not be null, but does not generally actively +defend itself against such misuse. Some C-style APIs explicitly accept +`null` as a no-op for usability's sake, and some of the JNI APIs +deliberately return an error code, instead of segfaulting, when passed +a `null`. + +Client-defined callbacks _must never throw exceptions_ unless _very +explitly documented_ as being throw-safe. Exceptions are generally +reserved for higher-level bindings which are constructed to +specifically deal with them and ensure that they do not leak C-level +resources. In some cases, callback handlers are permitted to throw, in +which cases they get translated to C-level result codes and/or +messages. If a callback which is not permitted to throw throws, its +exception may trigger debug output but will otherwise be suppressed. + +The reason some callbacks are permitted to throw and others not is +because all such callbacks act as proxies for C function callback +interfaces and some of those interfaces have no error-reporting +mechanism. Those which are capable of propagating errors back through +the library convert exceptions from callbacks into corresponding +C-level error information. Those which cannot propagate errors +necessarily suppress any exceptions in order to maintain the C-style +semantics of the APIs. + + +Unwieldy Constructs are Re-mapped +------------------------------------------------------------------------ + +Some constructs, when modelled 1-to-1 from C to Java, are unduly +clumsy to work with in Java because they try to shoehorn C's way of +doing certain things into Java's wildly different ways. The following +subsections cover those, starting with a verbose explanation and +demonstration of where such changes are "really necessary"... + +### Custom Collations + +A prime example of where interface changes for Java are necessary for +usability is [registration of a custom +collation](https://sqlite.org/c3ref/create_collation.html): + +```c +// C: +int sqlite3_create_collation(sqlite3 * db, const char * name, int eTextRep, + void *pUserData, + int (*xCompare)(void*,int,void const *,int,void const *)); + +int sqlite3_create_collation_v2(sqlite3 * db, const char * name, int eTextRep, + void *pUserData, + int (*xCompare)(void*,int,void const *,int,void const *), + void (*xDestroy)(void*)); +``` + +The `pUserData` object is optional client-defined state for the +`xCompare()` and/or `xDestroy()` callback functions, both of which are +passed that object as their first argument. That data is passed around +"externally" in C because that's how C models the world. If we were to +bind that part as-is to Java, the result would be awkward to use (^Yes, +we tried this.): + +```java +// Java: +int sqlite3_create_collation(sqlite3 db, String name, int eTextRep, + Object pUserData, xCompareType xCompare); + +int sqlite3_create_collation_v2(sqlite3 db, String name, int eTextRep, + Object pUserData, + xCompareType xCompare, xDestroyType xDestroy); +``` + +The awkwardness comes from (A) having two distinctly different objects +for callbacks and (B) having their internal state provided separately, +which is ill-fitting in Java. For the sake of usability, C APIs which +follow that pattern use a slightly different Java interface: + +```java +int sqlite3_create_collation(sqlite3 db, String name, int eTextRep, + SomeCallbackType collation); +``` + +Where the `Collation` class has an abstract `call()` method and +no-op `xDestroy()` method which can be overridden if needed, leading to +a much more Java-esque usage: + +```java +int rc = sqlite3_create_collation(db, "mycollation", SQLITE_UTF8, new SomeCallbackType(){ + + // Required comparison function: + @Override public int call(byte[] lhs, byte[] rhs){ ... } + + // Optional finalizer function: + @Override public void xDestroy(){ ... } + + // Optional local state: + private String localState1 = + "This is local state. There are many like it, but this one is mine."; + private MyStateType localState2 = new MyStateType(); + ... +}); +``` + +Noting that: + +- It is possible to bind in call-scope-local state via closures, if + desired, as opposed to packing it into the Collation object. + +- No capabilities of the C API are lost or unduly obscured via the + above API reshaping, so power users need not make any compromises. + +- In the specific example above, `sqlite3_create_collation_v2()` + becomes superfluous because the provided interface effectively + provides both the v1 and v2 interfaces, the difference being that + overriding the `xDestroy()` method effectively gives it v2 + semantics. + + +### User-defined SQL Functions (a.k.a. UDFs) + +The [`sqlite3_create_function()`](https://sqlite.org/c3ref/create_function.html) +family of APIs make heavy use of function pointers to provide +client-defined callbacks, necessitating interface changes in the JNI +binding. The Java API has only one core function-registration function: + +```java +int sqlite3_create_function(sqlite3 db, String funcName, int nArgs, + int encoding, SQLFunction func); +``` + +> Design question: does the encoding argument serve any purpose in + Java? That's as-yet undetermined. If not, it will be removed. + +`SQLFunction` is not used directly, but is instead instantiated via +one of its three subclasses: + +- `ScalarFunction` implements simple scalar functions using but a + single callback. +- `AggregateFunction` implements aggregate functions using two + callbacks. +- `WindowFunction` implements window functions using four + callbacks. + +Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for +`SQLFunction` for how it's used. + +Reminder: see the disclaimer at the top of this document regarding the +in-flux nature of this API. + +### And so on... + +Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and +`sqlite3_update_hook()`, use interfaces similar to those shown above. +Despite the changes in signature, the JNI layer makes every effort to +provide the same semantics as the C API documentation suggests. |