]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Initial check-in of JNI (Java Native Interface) bindings for the core C API.
authorstephan <stephan@noemail.net>
Thu, 27 Jul 2023 20:02:49 +0000 (20:02 +0000)
committerstephan <stephan@noemail.net>
Thu, 27 Jul 2023 20:02:49 +0000 (20:02 +0000)
FossilOrigin-Name: b5374b9ef58fa0be80aefccde0721f5599fb820464b13940b6361b9aa09a59d5

19 files changed:
ext/jni/GNUmakefile [new file with mode: 0644]
ext/jni/README.md [new file with mode: 0644]
ext/jni/src/c/sqlite3-jni.c [new file with mode: 0644]
ext/jni/src/c/sqlite3-jni.h [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/Collation.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/NativePointerHolder.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/OutputPointer.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/ProgressHandler.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/SQLFunction.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/SQLite3Jni.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/Tester1.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/Tracer.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/ValueHolder.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/sqlite3.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/sqlite3_context.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/sqlite3_stmt.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/sqlite3_value.java [new file with mode: 0644]
manifest
manifest.uuid

diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile
new file mode 100644 (file)
index 0000000..31a5e85
--- /dev/null
@@ -0,0 +1,168 @@
+# Quick-and-dirty makefile to bootstrap the sqlite3-jni project.  This
+# build assumes a Linux-like system.
+default: all
+
+JDK_HOME ?= $(HOME)/jdk/current
+# /usr/lib/jvm/default-javajava-19-openjdk-amd64
+bin.javac := $(JDK_HOME)/bin/javac
+bin.java  := $(JDK_HOME)/bin/java
+bin.jar   := $(JDK_HOME)/bin/jar
+ifeq (,$(wildcard $(JDK_HOME)))
+$(error set JDK_HOME to the top-most dir of your JDK installation.)
+endif
+MAKEFILE := $(lastword $(MAKEFILE_LIST))
+$(MAKEFILE):
+
+package.version := 0.0.1
+package.jar := sqlite3-jni-$(package.version).jar
+
+dir.top := ../..
+dir.jni := $(patsubst %/,%,$(dir $(MAKEFILE)))
+
+dir.src     := $(dir.jni)/src
+dir.src.c   := $(dir.src)/c
+dir.bld     := $(dir.jni)/bld
+dir.bld.c   := $(dir.bld)
+dir.src.jni := $(dir.src)/org/sqlite/jni
+$(dir.bld.c):
+       mkdir -p $@
+
+classpath := $(dir.src)
+CLEAN_FILES := $(package.jar)
+DISTCLEAN_FILES := $(dir.jni)/*~ $(dir.src.c)/*~ $(dir.src.jni)/*~
+
+sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
+.NOTPARALLEL: $(sqlite3-jni.h)
+SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java
+SQLite3Jni.class := $(subst .java,.class,$(SQLite3Jni.java))
+#$(sqlite3-jni.h): $(SQLite3Jni.java) $(dir.bld.c)
+#      $(bin.javac) -h $(dir $@) $<
+#all: $(sqlite3-jni.h)
+
+JAVA_FILES := $(wildcard $(dir.src.jni)/*.java)
+CLASS_FILES :=
+define DOTCLASS_DEPS
+$(1).class: $(1).java
+all: $(1).class
+CLASS_FILES += $(1).class
+endef
+$(foreach B,$(basename $(JAVA_FILES)),$(eval $(call DOTCLASS_DEPS,$(B))))
+javac.flags ?= -Xlint:unchecked -Xlint:deprecation
+java.flags ?=
+jnicheck ?= 1
+ifeq (1,$(jnicheck))
+  java.flags += -Xcheck:jni
+endif
+$(SQLite3Jni.class): $(JAVA_FILES)
+       $(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)
+all: $(SQLite3Jni.class)
+#.PHONY: classfiles
+
+########################################################################
+# Set up sqlite3.c and sqlite3.h...
+#
+# To build with SEE (https://sqlite.org/see), either put sqlite3-see.c
+# in the top of this build tree or pass
+# sqlite3.c=PATH_TO_sqlite3-see.c to the build. Note that only
+# encryption modules with no 3rd-party dependencies will currently
+# work here: AES256-OFB, AES128-OFB, and AES128-CCM. Not
+# coincidentally, those 3 modules are included in the sqlite3-see.c
+# bundle.
+#
+# A custom sqlite3.c must not have any spaces in its name.
+# $(sqlite3.canonical.c) must point to the sqlite3.c in
+# the sqlite3 canonical source tree, as that source file
+# is required for certain utility and test code.
+sqlite3.canonical.c := $(dir.top)/sqlite3.c
+sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
+sqlite3.h := $(dir.top)/sqlite3.h
+#ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c) 2>/dev/null))
+#  SQLITE_C_IS_SEE := 0
+#else
+#  SQLITE_C_IS_SEE := 1
+#  $(info This is an SEE build.)
+#endif
+
+.NOTPARALLEL: $(sqlite3.h)
+$(sqlite3.h):
+       $(MAKE) -C $(dir.top) sqlite3.c
+$(sqlite3.c): $(sqlite3.h)
+
+SQLITE_OPT := \
+  -DSQLITE_ENABLE_FTS5 \
+  -DSQLITE_ENABLE_RTREE \
+  -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
+  -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
+  -DSQLITE_ENABLE_STMTVTAB \
+  -DSQLITE_ENABLE_DBPAGE_VTAB \
+  -DSQLITE_ENABLE_DBSTAT_VTAB \
+  -DSQLITE_ENABLE_BYTECODE_VTAB \
+  -DSQLITE_ENABLE_OFFSET_SQL_FUNC \
+  -DSQLITE_OMIT_LOAD_EXTENSION \
+  -DSQLITE_OMIT_DEPRECATED \
+  -DSQLITE_OMIT_SHARED_CACHE \
+  -DSQLITE_OMIT_WAL \
+  -DSQLITE_THREADSAFE=0 \
+  -DSQLITE_TEMP_STORE=2 \
+  -DSQLITE_USE_URI=1 \
+  -DSQLITE_C=$(sqlite3.c) \
+  -DSQLITE_DEBUG
+# -DSQLITE_DEBUG is just to work around a -Wall warning
+# for a var which gets set in all builds but only read
+# via assert().
+
+sqlite3-jni.c := $(dir.src.c)/sqlite3-jni.c
+sqlite3-jni.o := $(dir.bld.c)/sqlite3-jni.o
+sqlite3-jni.h.in := $(dir.bld.c)/org_sqlite_jni_SQLite3Jni.h
+sqlite3-jni.h   := $(dir.src.c)/sqlite3-jni.h
+sqlite3-jni.dll := $(dir.bld.c)/libsqlite3-jni.so
+# ------------------------------^^^ lib prefix is requires
+# for java's System.loadLibrary().
+#sqlite3-jni.dll.cfiles := $(dir.src.c)
+sqlite3-jni.dll.cflags := \
+  -fPIC \
+  -I. \
+  -I$(dir $(sqlite3.h)) \
+  -I$(dir.src.c) \
+  -I$(JDK_HOME)/include \
+  $(patsubst %,-I%,$(patsubst %.h,,$(wildcard $(JDK_HOME)/include/*))) \
+  -Wall
+# Using (-Wall -Wextra) triggers an untennable number of
+# gcc warnings from sqlite3.c for mundane things like
+# unused parameters.
+#
+# The gross $(patsubst...) above is to include the platform-specific
+# subdir which lives under $(JDK_HOME)/include and is a required
+# include path for client-level code.
+########################################################################
+
+$(sqlite3-jni.h.in): $(dir.src.jni)/SQLite3Jni.class
+$(sqlite3-jni.h): $(sqlite3-jni.h.in) $(MAKEFILE)
+       cp -p $(sqlite3-jni.h.in) $@
+$(sqlite3-jni.c): $(sqlite3-jni.h) $(sqlite3.c) $(sqlite3.h)
+$(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
+       $(CC) $(sqlite3-jni.dll.cflags) $(SQLITE_OPT) \
+      $(sqlite3-jni.c) -shared -o $@
+all: $(sqlite3-jni.dll)
+
+test: $(SQLite3Jni.class) $(sqlite3-jni.dll)
+       $(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
+               $(java.flags) -cp $(classpath) org.sqlite.jni.Tester1
+
+$(package.jar): $(CLASS_FILES) $(MAKEFILE)
+       rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~
+       $(bin.jar) -cfe $@ org.sqlite.Tester1 -C src org -C src c
+
+jar: $(package.jar)
+
+CLEAN_FILES += $(dir.bld.c)/* \
+  $(dir.src.jni)/*.class \
+  $(sqlite3-jni.dll) \
+  hs_err_pid*.log
+
+.PHONY: clean distclean
+clean:
+       -rm -f $(CLEAN_FILES)
+distclean: clean
+       -rm -f $(DISTCLEAN_FILES)
+       -rm -fr $(dir.bld.c)
diff --git a/ext/jni/README.md b/ext/jni/README.md
new file mode 100644 (file)
index 0000000..0adf385
--- /dev/null
@@ -0,0 +1,213 @@
+SQLite3 via JNI
+========================================================================
+
+This repository houses a Java Native Interface (JNI) binding for the
+sqlite3 API.
+
+> **FOREWARNING:** this project 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.
+
+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](www:/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 do not directly interfere with each other.
+
+Non-goals:
+
+- Creation of high-level OO wrapper APIs. Clients are free to create
+  them off of the C-style API.
+
+
+Significant TODOs
+========================================================================
+
+- LOTS of APIs left to bind.
+
+- Bundling of the resulting class files into a jar. Bundling the DLLs
+  is a much larger problem, as they inherently have platform-specific
+  OS-level dependencies which we obviously cannot bundle.
+
+
+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:
+
+```
+$ export JDK_HOME=/path/to/jdk/root
+$ make
+$ make test
+$ make clean
+```
+
+<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. Exceptions 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.
+
+Golden Rule: _Never_ Throw from Callbacks
+------------------------------------------------------------------------
+
+JNI bindings which accept client-defined functions _must never throw
+exceptions_. There are _no exceptions_ to this rule. Exceptions are
+reserved for higher-level bindings which are constructed to
+specifically deal with them and ensure that they do not leak C-level
+resources. Some of the JNI bindings are provided as Java functions
+which expect this rule to always hold.
+
+UTF-8(-ish)
+------------------------------------------------------------------------
+
+SQLite internally uses UTF-8 encoding, whereas Java natively uses
+UTF-16.  Java JNI has routines for converting to and from UTF-8, _but_
+Java uses what its docs call "[modified UTF-8][modutf8]." Care must be
+taken when converting Java strings to UFF-8 to ensure that the proper
+conversion is performed. In short,
+`String.getBytes(StandardCharsets.UTF_8)` performs the proper
+conversion in Java, and there is no JNI C API for that conversion
+(JNI's `NewStringUTF()` returns MUTF-8).
+
+[modutf8]: https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8
+
+
+Unweildy 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](www:/c3ref/create_collation.html):
+
+```
+// 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:
+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:
+
+```
+int sqlite3_create_collation(sqlite3 db, String name, int eTextRep,
+                             Collation collation);
+```
+
+Where the `Collation` class has an abstract `xCompare()` method and
+no-op `xDestroy()` method which can be overridden if needed, leading to
+a much more Java-esque usage:
+
+```
+int rc = sqlite3_create_collation(db, "mycollation", SQLITE_UTF8, new Collation(){
+  // Required comparison function:
+  @Override public int xCompare(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 still possible to bind in call-scope-local state via closures,
+  but using member data for the Collation object is generally a better
+  fit for Java.
+
+- 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()`](www:/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 Jav API has only one core function-registration function:
+
+```
+int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
+                            int encoding, SQLFunction func);
+```
+
+`SQLFunction` is not used directly, but is instead instantiated via
+one of its three subclasses:
+
+- `SQLFunction.Scalar` implements simple scalar functions using but a
+  single callback.
+- `SQLFunction.Aggregate` implements aggregate functions using two
+  callbacks.
+- `SQLFunction.Window` implements window functions using four
+  callbacks.
+
+Search [`Tester1.java`](/file/src/org/sqlite/jni/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.
+
+[jsrc]: /file/
+[www]: https://sqlite.org
diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c
new file mode 100644 (file)
index 0000000..ba892af
--- /dev/null
@@ -0,0 +1,1935 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file implements the JNI bindings declared in
+** org.sqlite.jni.SQLiteJni (from which sqlite3-jni.h is generated).
+*/
+
+/*
+** Define any SQLITE_... config defaults we want if they aren't
+** overridden by the builder. Please keep these alphabetized.
+*/
+
+/**********************************************************************/
+/* SQLITE_D... */
+#ifndef SQLITE_DEFAULT_CACHE_SIZE
+# define SQLITE_DEFAULT_CACHE_SIZE -16384
+#endif
+#if !defined(SQLITE_DEFAULT_PAGE_SIZE)
+# define SQLITE_DEFAULT_PAGE_SIZE 8192
+#endif
+#ifndef SQLITE_DEFAULT_UNIX_VFS
+# define SQLITE_DEFAULT_UNIX_VFS "unix"
+#endif
+#undef SQLITE_DQS
+#define SQLITE_DQS 0
+
+/**********************************************************************/
+/* SQLITE_ENABLE_... */
+#ifndef SQLITE_ENABLE_BYTECODE_VTAB
+#  define SQLITE_ENABLE_BYTECODE_VTAB 1
+#endif
+#ifndef SQLITE_ENABLE_DBPAGE_VTAB
+#  define SQLITE_ENABLE_DBPAGE_VTAB 1
+#endif
+#ifndef SQLITE_ENABLE_DBSTAT_VTAB
+#  define SQLITE_ENABLE_DBSTAT_VTAB 1
+#endif
+#ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#  define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
+#endif
+#ifndef SQLITE_ENABLE_FTS4
+#  define SQLITE_ENABLE_FTS4 1
+#endif
+#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
+#  define SQLITE_ENABLE_MATH_FUNCTIONS 1
+#endif
+#ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC
+#  define SQLITE_ENABLE_OFFSET_SQL_FUNC 1
+#endif
+#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
+#  define SQLITE_ENABLE_PREUPDATE_HOOK 1 /*required by session extension*/
+#endif
+#ifndef SQLITE_ENABLE_RTREE
+#  define SQLITE_ENABLE_RTREE 1
+#endif
+#ifndef SQLITE_ENABLE_SESSION
+#  define SQLITE_ENABLE_SESSION 1
+#endif
+#ifndef SQLITE_ENABLE_STMTVTAB
+#  define SQLITE_ENABLE_STMTVTAB 1
+#endif
+#ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+#  define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+#endif
+
+/**********************************************************************/
+/* SQLITE_M... */
+#ifndef SQLITE_MAX_ALLOCATION_SIZE
+# define SQLITE_MAX_ALLOCATION_SIZE 0x1fffffff
+#endif
+
+/**********************************************************************/
+/* SQLITE_O... */
+#ifndef SQLITE_OMIT_DEPRECATED
+# define SQLITE_OMIT_DEPRECATED 1
+#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+#endif
+#ifndef SQLITE_OMIT_SHARED_CACHE
+# define SQLITE_OMIT_SHARED_CACHE 1
+#endif
+#ifdef SQLITE_OMIT_UTF16
+/* UTF16 is required for java */
+# undef SQLITE_OMIT_UTF16 1
+#endif
+
+/**********************************************************************/
+/* SQLITE_T... */
+#ifndef SQLITE_TEMP_STORE
+# define SQLITE_TEMP_STORE 2
+#endif
+#ifndef SQLITE_THREADSAFE
+# define SQLITE_THREADSAFE 0
+#endif
+
+/**********************************************************************/
+/* SQLITE_USE_... */
+#ifndef SQLITE_USE_URI
+#  define SQLITE_USE_URI 1
+#endif
+
+
+/*
+** Which sqlite3.c we're using needs to be configurable to enable
+** building against a custom copy, e.g. the SEE variant. We have to
+** include sqlite3.c, as opposed to sqlite3.h, in order to get access
+** to SQLITE_MAX_... and friends. This increases the rebuild time
+** considerably but we need this in order to keep the exported values
+** of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C build.
+*/
+#ifndef SQLITE_C
+# define SQLITE_C sqlite3.c
+#endif
+#define INC__STRINGIFY_(f) #f
+#define INC__STRINGIFY(f) INC__STRINGIFY_(f)
+#include INC__STRINGIFY(SQLITE_C)
+#undef INC__STRINGIFY_
+#undef INC__STRINGIFY
+#undef SQLITE_C
+
+#include "sqlite3-jni.h"
+#include <stdio.h> /* only for testing/debugging */
+#include <assert.h>
+
+/* Only for debugging */
+#define MARKER(pfexp)                                               \
+  do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__);   \
+    printf pfexp;                                                   \
+  } while(0)
+
+/* Creates a verbose JNI function name. */
+#define JFuncName(Suffix) \
+  Java_org_sqlite_jni_SQLite3Jni_sqlite3_ ## Suffix
+
+/* Prologue for JNI functions. */
+#define JDECL(ReturnType,Suffix)                \
+  JNIEXPORT ReturnType JNICALL                  \
+  JFuncName(Suffix)
+/* First 2 parameters to all JNI bindings. */
+#define JENV_JSELF JNIEnv * env, jobject jSelf
+/* Helper to squelch -Xcheck:jni warnings about
+   not having checked for exceptions. */
+#define IFTHREW if((*env)->ExceptionCheck(env))
+#define EXCEPTION_IGNORE (void)((*env)->ExceptionCheck(env))
+#define EXCEPTION_CLEAR (*env)->ExceptionClear(env)
+#define EXCEPTION_REPORT (*env)->ExceptionDescribe(env)
+#define IFTHREW_REPORT IFTHREW EXCEPTION_REPORT
+
+
+#define PtrGet_sqlite3(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3)
+#define PtrGet_sqlite3_stmt(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_stmt)
+#define PtrGet_sqlite3_value(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_value)
+#define PtrGet_sqlite3_context(OBJ) getNativePointer(env,OBJ,ClassNames.sqlite3_context)
+#define REF_G(VAR) (*env)->NewGlobalRef(env, VAR)
+/*#define REF_L(VAR) (*env)->NewLocalRef(env, VAR)*/
+#define UNREF_G(VAR) if(VAR) (*env)->DeleteGlobalRef(env, (VAR))
+#define UNREF_L(VAR) if(VAR) (*env)->DeleteLocalRef(env, (VAR))
+
+/**
+   Constant string class names used as keys for S3Global_nph_cache() and
+   friends.
+*/
+static const struct {
+  const char * const sqlite3;
+  const char * const sqlite3_stmt;
+  const char * const sqlite3_context;
+  const char * const sqlite3_value;
+  const char * const OutputPointer_Int32;
+} ClassNames = {
+  "org/sqlite/jni/sqlite3",
+  "org/sqlite/jni/sqlite3_stmt",
+  "org/sqlite/jni/sqlite3_context",
+  "org/sqlite/jni/sqlite3_value",
+  "org/sqlite/jni/OutputPointer$Int32"
+};
+
+/** Create a trivial JNI wrapper for (int CName(void)). */
+#define WRAP_INT_VOID(JniNameSuffix,CName) \
+  JDECL(jint,JniNameSuffix)(JNIEnv *env, jobject jSelf){ \
+    return (jint)CName(); \
+  }
+
+#define WRAP_INT_INT(JniNameSuffix,CName)               \
+  JDECL(jint,JniNameSuffix)(JNIEnv *env, jobject jSelf, jint arg){   \
+    return (jint)CName((int)arg);                                    \
+  }
+
+/** Create a trivial JNI wrapper for (const mutf8_string *
+    CName(void)). This is only value for functions which are known to
+    return ASCII or text compatible with Modified UTF8. */
+#define WRAP_MUTF8_VOID(JniNameSuffix,CName)                             \
+  JDECL(jstring,JniNameSuffix)(JENV_JSELF){                  \
+    return (*env)->NewStringUTF( env, CName() );                        \
+  }
+/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*)). */
+#define WRAP_INT_STMT(JniNameSuffix,CName) \
+  JDECL(jint,JniNameSuffix)(JENV_JSELF, jobject jpStmt){   \
+    jint const rc = (jint)CName(PtrGet_sqlite3_stmt(jpStmt)); \
+    EXCEPTION_IGNORE /* squelch -Xcheck:jni */;        \
+    return rc; \
+  }
+/** Create a trivial JNI wrapper for (int CName(sqlite3*)). */
+#define WRAP_INT_DB(JniNameSuffix,CName) \
+  JDECL(jint,JniNameSuffix)(JENV_JSELF, jobject pDb){   \
+    return (jint)CName(PtrGet_sqlite3(pDb)); \
+  }
+/** Create a trivial JNI wrapper for (int64 CName(sqlite3*)). */
+#define WRAP_INT64_DB(JniNameSuffix,CName) \
+  JDECL(jlong,JniNameSuffix)(JENV_JSELF, jobject pDb){   \
+    return (jlong)CName(PtrGet_sqlite3(pDb)); \
+  }
+/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*,int)). */
+#define WRAP_INT_STMT_INT(JniNameSuffix,CName) \
+  JDECL(jint,JniNameSuffix)(JENV_JSELF, jobject pStmt, jint n){ \
+    return (jint)CName(PtrGet_sqlite3_stmt(pStmt), (int)n);                          \
+  }
+/** Create a trivial JNI wrapper for (jstring CName(sqlite3_stmt*,int)). */
+#define WRAP_STR_STMT_INT(JniNameSuffix,CName) \
+  JDECL(jstring,JniNameSuffix)(JENV_JSELF, jobject pStmt, jint ndx){ \
+    return (*env)->NewStringUTF(env, CName(PtrGet_sqlite3_stmt(pStmt), (int)ndx));  \
+  }
+/** Create a trivial JNI wrapper for (int CName(sqlite3_value*)). */
+#define WRAP_INT_SVALUE(JniNameSuffix,CName) \
+  JDECL(jint,JniNameSuffix)(JENV_JSELF, jobject jpSValue){   \
+    return (jint)CName(PtrGet_sqlite3_value(jpSValue)); \
+  }
+
+/* Helpers for jstring and jbyteArray. */
+#define JSTR_TOC(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
+#define JSTR_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
+#define JBA_TOC(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
+#define JBA_RELEASE(ARG,VAR) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)
+
+/* Marker for code which needs(?) to be made thread-safe. */
+#define FIXME_THREADING
+
+enum {
+  /**
+     Size of the per-JNIEnv cache. We have no way of knowing how many
+     distinct JNIEnv's will be used in any given run, but know that it
+     will normally be only 1. Perhaps (just speculating) differen
+     threads use separate JNIEnvs? If that's the case, we don't(?)
+     have enough info to evict from the cache when those JNIEnvs
+     expire.
+
+     If this ever fills up, we can refactor this to dynamically
+     allocate them.
+  */
+  JNIEnvCache_SIZE = 10,
+  /**
+    Need enough space for (only) the library's NativePointerHolder
+    types, a fixed count known at build-time. If we add more than this
+    a fatal error will be triggered with a reminder to increase this.
+  */
+  NphCache_SIZE = 10
+};
+
+/**
+   Cache for NativePointerHolder lookups.
+*/
+typedef struct NphCacheLine NphCacheLine;
+struct NphCacheLine {
+  const char * zClassName /* "full/class/Name" */;
+  jclass klazz      /* global ref to concrete NPH class */;
+  jmethodID midSet  /* setNativePointer() */;
+  jmethodID midGet  /* getNativePointer() */;
+  jmethodID midCtor /* constructor */;
+};
+
+typedef struct JNIEnvCacheLine JNIEnvCacheLine;
+struct JNIEnvCacheLine {
+  JNIEnv *env;
+  jclass globalClassObj  /* global ref to java.lang.Object */;
+  jclass globalClassLong /* global ref to java.lang.Long */;
+  jmethodID ctorLong1    /* the Long(long) constructor */;
+  struct NphCacheLine nph[NphCache_SIZE];
+};
+typedef struct JNIEnvCache JNIEnvCache;
+struct JNIEnvCache {
+  struct JNIEnvCacheLine lines[JNIEnvCache_SIZE];
+  unsigned int used;
+};
+
+static void NphCacheLine_clear(JNIEnv *env, NphCacheLine * p){
+  UNREF_G(p->klazz);
+  memset(p, 0, sizeof(NphCacheLine));
+}
+
+static void JNIEnvCacheLine_clear(JNIEnvCacheLine * p){
+  JNIEnv *env = p->env;
+  int i;
+  if(env){
+    UNREF_G(p->globalClassObj);
+    UNREF_G(p->globalClassLong);
+    i = 0;
+    for( ; i < NphCache_SIZE; ++i){
+      NphCacheLine_clear(env, &p->nph[i]);
+    }
+  }
+}
+
+static void JNIEnvCache_clear(JNIEnvCache * p){
+  unsigned int i = 0;
+  for( ; i < p->used; ++i ){
+    JNIEnvCacheLine_clear( &p->lines[i] );
+  }
+  memset(p, 0, sizeof(JNIEnvCache));
+}
+
+/**
+   Per-(sqlite3*) state for bindings which do not have their own
+   finalizer functions, e.g. tracing and commit/rollback hooks.  This
+   state is allocated as needed, cleaned up in sqlite3_close(_v2)(),
+   and recycled when possible. It is freed during sqlite3_shutdown().
+
+   Open questions:
+
+   - Do we need to do a (JNIEnv*) for the db and each set of binding
+   data (since they can(?) hypothetically be set via multiple JNIEnv
+   objects)?
+*/
+typedef struct PerDbState PerDbState;
+struct PerDbState {
+  JNIEnv *env;
+  sqlite3 * pDb;
+  PerDbState * pNext;
+  PerDbState * pPrev;
+  struct {
+    jobject jObj;
+    jmethodID midCallback;
+  } trace;
+  struct {
+    jobject jObj;
+    jmethodID midCallback;
+  } progress;
+  struct {
+    jobject jObj;
+    jmethodID midCallback;
+  } commitHook;
+  struct {
+    jobject jObj;
+    jmethodID midCallback;
+  } rollbackHook;
+};
+
+static struct {
+  /**
+     According to: https://developer.ibm.com/articles/j-jni/
+
+     > A thread can get a JNIEnv by calling GetEnv() using the JNI
+       invocation interface through a JavaVM object. The JavaVM object
+       itself can be obtained by calling the JNI GetJavaVM() method
+       using a JNIEnv object and can be cached and shared across
+       threads. Caching a copy of the JavaVM object enables any thread
+       with access to the cached object to get access to its own
+       JNIEnv when necessary.
+  */
+  JavaVM * jvm;
+  struct JNIEnvCache envCache;
+  struct {
+    PerDbState * aUsed;
+    PerDbState * aFree;
+  } perDb;
+} S3Global;
+
+/**
+   sqlite3_malloc() proxy which fails fatally on OOM.  This should
+   only be used for routines which manage global state and have no
+   recovery strategy for OOM. For sqlite3 API which can reasonably
+   return SQLITE_NOMEM, sqlite3_malloc() should be used instead.
+*/
+static void * s3jni_malloc(JNIEnv *env, size_t n){
+  void * rv = sqlite3_malloc(n);
+  if(n && !rv){
+    (*env)->FatalError(env, "Out of memory.") /* does not return */;
+  }
+  return rv;
+}
+
+static void s3jni_free(void * p){
+  if(p) sqlite3_free(p);
+}
+/**
+   Extracts the new PerDbState instance from the free-list, or
+   allocates one if needed, associats it with pDb, and returns.
+   Returns NULL on OOM.
+*/
+static PerDbState * PerDbState_alloc(JNIEnv *env, sqlite3 *pDb){
+  PerDbState * rv;
+  assert( pDb );
+  if(S3Global.perDb.aFree){
+    rv = S3Global.perDb.aFree;
+    S3Global.perDb.aFree = rv->pNext;
+    if(rv->pNext){
+      assert(rv->pNext->pPrev == rv);
+      assert(rv->pNext == rv->pNext->pPrev);
+      rv->pNext->pPrev = 0;
+      rv->pNext = 0;
+    }
+  }else{
+    rv = s3jni_malloc(env, sizeof(PerDbState));
+    if(rv){
+      memset(rv, 0, sizeof(PerDbState));
+      rv->pNext = S3Global.perDb.aUsed;
+      S3Global.perDb.aUsed = rv;
+      if(rv->pNext){
+        assert(!rv->pNext->pPrev);
+        rv->pNext->pPrev = rv;
+      }
+    }
+  }
+  if(rv){
+    rv->pDb = pDb;
+    rv->env = env;
+  }
+  return rv;
+}
+
+/**
+   Clears s's state and moves it to the free-list.
+*/
+FIXME_THREADING
+static void PerDbState_set_aside(PerDbState *s){
+  if(s){
+    JNIEnv * const env = s->env;
+    assert(s->pDb && "Else this object is already in the free-list.");
+    if(s->pNext) s->pNext->pPrev = s->pPrev;
+    if(s->pPrev) s->pPrev->pNext = s->pNext;
+    else if(S3Global.perDb.aUsed == s){
+      assert(!s->pPrev);
+      S3Global.perDb.aUsed = s->pNext;
+    }
+    UNREF_G(s->trace.jObj);
+    UNREF_G(s->progress.jObj);
+    UNREF_G(s->commitHook.jObj);
+    UNREF_G(s->rollbackHook.jObj);
+    s->env = 0;
+    s->pDb = 0;
+    s->pPrev = 0;
+    s->pNext = S3Global.perDb.aFree;
+    S3Global.perDb.aFree = s;
+  }
+}
+
+/**
+   Returns the PerDbState object for the given db. If allocIfNeeded is
+   true then a new instance will be allocated if no mapping currently
+   exists, else NULL is returned if no mapping is found.
+
+*/
+FIXME_THREADING
+static PerDbState * PerDbState_for_db(JNIEnv *env, sqlite3 *pDb, int allocIfNeeded){
+  PerDbState * s = S3Global.perDb.aUsed;
+  for( ; s; s = s->pNext){
+    if(s->pDb == pDb) return s;
+  }
+  if(allocIfNeeded) s = PerDbState_alloc(env, pDb);
+  return s;
+}
+
+/**
+   Cleans up and frees all state in S3Global.perDb.
+*/
+FIXME_THREADING
+static void PerDbState_free_all(void){
+  PerDbState * pS = S3Global.perDb.aUsed;
+  PerDbState * pSNext = 0;
+  for( ; pS; pS = pSNext ){
+    pSNext = pS->pNext;
+    PerDbState_set_aside(pS);
+    assert(pSNext ? !pSNext->pPrev : 1);
+  }
+  assert( 0==S3Global.perDb.aUsed );
+  pS = S3Global.perDb.aFree;
+  S3Global.perDb.aFree = 0;
+  pSNext = 0;
+  for( ; pS; pS = pSNext ){
+    pSNext = pS->pNext;
+    s3jni_free(pSNext);
+  }
+}
+
+/**
+   Fetches the S3Global.envCache row for the given env, allocing
+   a row if needed. When a row is allocated, its state is initialized
+   insofar as possible. Calls (*env)->FatalError() if the cache
+   fills up. That's hypothetically possible but "shouldn't happen."
+   If it does, we can dynamically allocate these instead.
+
+*/
+FIXME_THREADING
+static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
+  struct JNIEnvCacheLine * row = 0;
+  int i = 0;
+  for( ; i < JNIEnvCache_SIZE; ++i ){
+    row = &S3Global.envCache.lines[i];
+    if(row->env == env) return row;
+    else if(!row->env) break;
+  }
+  if(i == JNIEnvCache_SIZE){
+    (*env)->FatalError(env, "Maintenance required: JNIEnvCache is full.");
+    return NULL;
+  }
+  row->env = env;
+  row->globalClassObj = REF_G((*env)->FindClass(env,"java/lang/Object"));
+  row->globalClassLong = REF_G((*env)->FindClass(env,"java/lang/Long"));
+  row->ctorLong1 = (*env)->GetMethodID(env, row->globalClassLong,
+                                       "<init>", "(J)V");
+  ++S3Global.envCache.used;
+  //MARKER(("Added S3Global.envCache entry #%d.\n", S3Global.envCache.used));
+  return row;
+}
+
+/**
+   Searches the NativePointerHolder cache for the given combination.
+   If it finds one, it returns it as-is. If it doesn't AND the cache
+   has a free slot, it populates that slot with (env, zClassName,
+   klazz) and returns it. If the cache is full with no match it
+   returns NULL.
+
+   It is up to the caller to populate the other members of the returned
+   object if needed.
+
+   zClassName must be a static string so we can use its address as a
+   cache key.
+
+   This simple cache catches the overwhelming majority of searches
+   (>95%) in the current (2023-07-24) tests.
+*/
+FIXME_THREADING
+static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassName){
+  /**
+     According to:
+
+     https://developer.ibm.com/articles/j-jni/
+
+     > ... the IDs returned for a given class don't change for the
+     lifetime of the JVM process. But the call to get the field or
+     method can require significant work in the JVM, because
+     fields and methods might have been inherited from
+     superclasses, making the JVM walk up the class hierarchy to
+     find them. Because the IDs are the same for a given class,
+     you should look them up once and then reuse them. Similarly,
+     looking up class objects can be expensive, so they should be
+     cached as well.
+  */
+  struct JNIEnvCacheLine * const envRow = S3Global_env_cache(env);
+  struct NphCacheLine * freeSlot = 0;
+  struct NphCacheLine * cacheLine = 0;
+  int i;
+  assert(envRow);
+  for( i = 0; i < NphCache_SIZE; ++i ){
+    cacheLine = &envRow->nph[i];
+    if(zClassName == cacheLine->zClassName){
+#if 0
+      static unsigned int n = 0;
+      MARKER(("Cache hit #%u %s klazz@%p getter@%p, setter@%p, ctor@%p\n",
+              ++n, zClassName, cacheLine->klazz, cacheLine->midGet,
+              cacheLine->midSet, cacheLine->midCtor));
+#endif
+      assert(cacheLine->klazz);
+      return cacheLine;
+    }else if(!freeSlot && !cacheLine->zClassName){
+      freeSlot = cacheLine;
+    }
+  }
+  if(freeSlot){
+    freeSlot->zClassName = zClassName;
+    freeSlot->klazz = REF_G((*env)->FindClass(env, zClassName));
+#if 0
+    static unsigned int cacheMisses = 0;
+    MARKER(("Cache miss #%u %s klazz@%p getter@%p, setter@%p, ctor@%p\n",
+            ++cacheMisses, zClassName, freeSlot->klazz,
+            freeSlot->midGet, freeSlot->midSet, freeSlot->midCtor));
+#endif
+  }else{
+    (*env)->FatalError(env, "MAINTENANCE REQUIRED: NphCache_SIZE is too low.");
+  }
+  return freeSlot;
+}
+
+/**
+   Sets a native ptr value in NativePointerHolder object ppOut.
+   zClassName must be a static string so we can use its address
+   as a cache key.
+*/
+static void setNativePointer(JNIEnv * env, jobject ppOut, void * p,
+                             const char *zClassName){
+  jmethodID setter = 0;
+  struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName);
+  if(cacheLine && cacheLine->klazz && cacheLine->midSet){
+    assert(zClassName == cacheLine->zClassName);
+    setter = cacheLine->midSet;
+    assert(setter);
+  }else{
+    jclass const klazz =
+      cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, ppOut);
+    setter = (*env)->GetMethodID(env, klazz, "setNativePointer", "(J)V");
+    if(cacheLine){
+      assert(cacheLine->klazz);
+      assert(!cacheLine->midSet);
+      assert(zClassName == cacheLine->zClassName);
+      cacheLine->midSet = setter;
+    }
+  }
+  (*env)->CallVoidMethod(env, ppOut, setter, (jlong)p);
+  IFTHREW_REPORT;
+}
+
+/**
+   Fetches a native ptr value from NativePointerHolder object ppOut.
+   zClassName must be a static string so we can use its address as a
+   cache key.
+*/
+static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassName){
+  if( 0==pObj ) return 0;
+  else{
+    jmethodID getter = 0;
+    void * rv = 0;
+    struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName);
+    if(cacheLine && cacheLine->midGet){
+      getter = cacheLine->midGet;
+    }else{
+      jclass const klazz =
+        cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, pObj);
+      getter = (*env)->GetMethodID(env, klazz, "getNativePointer", "()J");
+      if(cacheLine){
+        assert(cacheLine->klazz);
+        assert(zClassName == cacheLine->zClassName);
+        cacheLine->midGet = getter;
+      }
+    }
+    rv = (void*)(*env)->CallLongMethod(env, pObj, getter);
+    IFTHREW_REPORT;
+    return rv;
+  }
+}
+
+/*
+** This function is NOT part of the sqlite3 public API. It is strictly
+** for use by the sqlite project's own Java/JNI bindings.
+**
+** For purposes of certain hand-crafted JNI function bindings, we
+** need a way of reporting errors which is consistent with the rest of
+** the C API, as opposed to throwing JS exceptions. To that end, this
+** internal-use-only function is a thin proxy around
+** sqlite3ErrorWithMessage(). The intent is that it only be used from
+** JNI bindings such as sqlite3_prepare_v2/v3(), and definitely not
+** from client code.
+**
+** Returns err_code.
+*/
+static int s3jni_db_error(sqlite3*db, int err_code, const char *zMsg){
+  if( db!=0 ){
+    if( 0!=zMsg ){
+      const int nMsg = sqlite3Strlen30(zMsg);
+      sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
+    }else{
+      sqlite3ErrorWithMsg(db, err_code, NULL);
+    }
+  }
+  return err_code;
+}
+
+
+
+/* Sets a native int32 value in OutputPointer.Int32 object ppOut. */
+static void setOutputInt32(JNIEnv * env, jobject ppOut, int v){
+  jmethodID setter = 0;
+  struct NphCacheLine * const cacheLine =
+    S3Global_nph_cache(env, ClassNames.OutputPointer_Int32);
+  if(cacheLine && cacheLine->klazz && cacheLine->midSet){
+    setter = cacheLine->midSet;
+  }else{
+    const jclass klazz = (*env)->GetObjectClass(env, ppOut);
+    setter = (*env)->GetMethodID(env, klazz, "setValue", "(I)V");
+    if(cacheLine){
+      assert(!cacheLine->midSet);
+      cacheLine->midSet = setter;
+    }
+  }
+  (*env)->CallVoidMethod(env, ppOut, setter, (jint)v);
+  IFTHREW_REPORT;
+}
+
+#if 0
+/* Fetches a native int32 value from OutputPointer.Int32 object pObj. */
+static int getOutputInt(JNIEnv * env, jobject pObj){
+  const jclass klazz = (*env)->GetObjectClass(env, pObj);
+  const jmethodID getter =
+    (*env)->GetMethodID(env, klazz, "getValue", "(V)I;");
+  return (int)(*env)->CallIntMethod(env, pObj, getter);
+}
+#define VAL_GET_INT(OBJ) getOutputInt(env, OBJ)
+#endif
+
+static int encodingTypeIsValid(int eTextRep){
+  switch(eTextRep){
+    case SQLITE_UTF8: case SQLITE_UTF16:
+    case SQLITE_UTF16LE: case SQLITE_UTF16BE:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+/**
+   State for binding Java-side collation sequences.
+*/
+typedef struct {
+  jclass klazz         /* Collation object's class */;
+  jobject oCollation   /* Collation instance */;
+  jmethodID midCompare /* cached xCompare */;
+  JNIEnv * env;        /* env registered from */;
+} CollationState;
+
+static CollationState * CollationState_alloc(void){
+  CollationState * rc = sqlite3_malloc(sizeof(CollationState));
+  if(rc) memset(rc, 0, sizeof(CollationState));
+  return rc;
+}
+
+static void CollationState_free(CollationState * cs){
+  JNIEnv * const env = cs->env;
+  if(env){
+    //MARKER(("Collation cleanup...\n"));
+    if(cs->oCollation) UNREF_G(cs->oCollation);
+    if(cs->klazz) UNREF_G(cs->klazz);
+  }
+  sqlite3_free(cs);
+}
+
+static int collation_xCompare_proxy(void *pArg, int nLhs, const void *lhs,
+                                    int nRhs, const void *rhs){
+  CollationState * const cs = (CollationState*)pArg;
+  JNIEnv * env = cs->env;
+  jint rc;
+  jbyteArray jbaLhs = (*env)->NewByteArray(env, (jint)nLhs);
+  jbyteArray jbaRhs = (*env)->NewByteArray(env, (jint)nRhs);
+  //MARKER(("native xCompare nLhs=%d nRhs=%d\n", nLhs, nRhs));
+  (*env)->SetByteArrayRegion(env, jbaLhs, 0, (jint)nLhs, (const jbyte*)lhs);
+  (*env)->SetByteArrayRegion(env, jbaRhs, 0, (jint)nRhs, (const jbyte*)rhs);
+  rc = (*env)->CallIntMethod(env, cs->oCollation, cs->midCompare,
+                             jbaLhs, jbaRhs);
+  EXCEPTION_IGNORE;
+  UNREF_L(jbaLhs);
+  UNREF_L(jbaRhs);
+  return (int)rc;
+}
+
+static void collation_xDestroy_proxy(void *pArg){
+  CollationState * const cs = (CollationState*)pArg;
+  if(cs->oCollation){
+    JNIEnv * const env = cs->env;
+    const jmethodID method = (*env)->GetMethodID(env, cs->klazz, "xDestroy",
+                                                 "()V");
+    //MARKER(("Calling Collation.xDestroy()...\n"));
+    (*env)->CallVoidMethod(env, cs->oCollation, method);
+    IFTHREW {
+      MARKER(("Collation.xDestroy() threw. Ignoring!\n"));
+      EXCEPTION_REPORT;
+      EXCEPTION_CLEAR;
+    }
+    //MARKER(("Returned from Collation.xDestroy().\n"));
+  }
+  CollationState_free(cs);
+}
+
+/* State for sqlite3_result_java_object() and
+   sqlite3_value_java_object(). */
+typedef struct {
+  /* POTENTIAL bug: the JNI docs say that the JNIEnv pointer
+     is guaranteed to resolve the same for the same contexts,
+     but the docs are unclear as to whether it's the (JNIEnv *env)
+     or (*env) which resolves consistently.
+
+     This posts claims it's unsave to cache JNIEnv at all, even when
+     it's always used in the same thread:
+
+     https://stackoverflow.com/questions/12420463
+
+     And this one seems to contradict that:
+
+     https://stackoverflow.com/questions/13964608
+
+     For later reference:
+
+     https://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/design.html#wp1242
+
+     https://developer.android.com/training/articles/perf-jni
+
+     The later has the following say about caching:
+
+     > If performance is important, it's useful to look the
+       [class/method ID] values up once and cache the results in your
+       native code. Because there is a limit of one JavaVM per
+       process, it's reasonable to store this data in a static local
+       structure. ... The class references, field IDs, and method IDs
+       are guaranteed valid until the class is unloaded. Classes are
+       only unloaded if all classes associated with a ClassLoader can
+       be garbage collected, which is rare but will not be impossible
+       in Android. Note however that the jclass is a class reference
+       and must be protected with a call to NewGlobalRef (see the next
+       section).
+  */
+  JNIEnv * env;
+  jobject jObj;
+} ResultJavaVal;
+
+/* For use with sqlite3_result/value_pointer() */
+#define RESULT_JAVA_VAL_STRING "ResultJavaVal"
+
+static ResultJavaVal * ResultJavaVal_alloc(JNIEnv *env, jobject jObj){
+  ResultJavaVal * rv = sqlite3_malloc(sizeof(ResultJavaVal));
+  if(rv){
+    rv->env = env;
+    rv->jObj = jObj ? REF_G(jObj) : 0;
+  }
+  return rv;
+}
+
+static void ResultJavaVal_finalizer(void *v){
+  if(v){
+    ResultJavaVal * const rv = (ResultJavaVal*)v;
+    if(rv->jObj) (*(rv->env))->DeleteGlobalRef(rv->env, rv->jObj);
+    sqlite3_free(rv);
+  }
+}
+
+
+
+/**
+   Returns a new Java instance of the class named by zClassName, which
+   MUST be interface-compatible with NativePointerHolder and MUST have
+   a no-arg constructor. Its setNativePointer() method is passed
+   pNative. Hypothetically returns NULL if Java fails to allocate, but
+   the JNI docs are not entirely clear on that detail.
+
+   Always use a string literal for the 2nd argument so that we can use
+   its address as a cache key.
+*/
+static jobject new_NativePointerHolder_object(JNIEnv *env, const char *zClassName,
+                                              void * pNative){
+  jobject rv = 0;
+  jclass klazz = 0;
+  jmethodID ctor = 0;
+  struct NphCacheLine * const cacheLine =
+    S3Global_nph_cache(env, zClassName);
+  if(cacheLine && cacheLine->midCtor){
+    assert( cacheLine->klazz );
+    klazz = cacheLine->klazz;
+    ctor = cacheLine->midCtor;
+  }else{
+    klazz = cacheLine
+      ? cacheLine->klazz
+      : (*env)->FindClass(env, zClassName);
+    ctor = (*env)->GetMethodID(env, klazz, "<init>", "()V");
+    if(cacheLine){
+      assert(zClassName == cacheLine->zClassName);
+      assert(cacheLine->klazz);
+      assert(!cacheLine->midCtor);
+      cacheLine->midCtor = ctor;
+    }
+  }
+  assert(klazz);
+  assert(ctor);
+  rv = (*env)->NewObject(env, klazz, ctor);
+  if(rv) setNativePointer(env, rv, pNative, zClassName);
+  return rv;
+}
+
+static jobject new_sqlite3_value_wrapper(JNIEnv *env, sqlite3_value *sv){
+  return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3_value", sv);
+}
+
+static jobject new_sqlite3_context_wrapper(JNIEnv *env, sqlite3_context *sv){
+  return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3_context", sv);
+}
+
+static jobject new_sqlite3_wrapper(JNIEnv *env, sqlite3 *sv){
+  return new_NativePointerHolder_object(env, "org/sqlite/jni/sqlite3", sv);
+}
+
+enum UDFType {
+  UDF_SCALAR = 1,
+  UDF_AGGREGATE,
+  UDF_WINDOW,
+  UDF_UNKNOWN_TYPE/*for error propagation*/
+};
+
+typedef void (*udf_xFunc_f)(sqlite3_context*,int,sqlite3_value**);
+typedef void (*udf_xStep_f)(sqlite3_context*,int,sqlite3_value**);
+typedef void (*udf_xFinal_f)(sqlite3_context*);
+/*typedef void (*udf_xValue_f)(sqlite3_context*);*/
+/*typedef void (*udf_xInverse_f)(sqlite3_context*,int,sqlite3_value**);*/
+
+/**
+   State for binding Java-side UDFs.
+*/
+typedef struct {
+  JNIEnv * env;         /* env registered from */;
+  jobject jObj          /* SQLFunction instance */;
+  jclass klazz          /* jObj's class */;
+  char * zFuncName      /* Only for error reporting and debug logging */;
+  enum UDFType type;
+  /** Method IDs for the various UDF methods. */
+  jmethodID jmidxFunc;
+  jmethodID jmidxStep;
+  jmethodID jmidxFinal;
+  jmethodID jmidxValue;
+  jmethodID jmidxInverse;
+} UDFState;
+
+static UDFState * UDFState_alloc(JNIEnv *env, jobject jObj){
+  UDFState * const s = sqlite3_malloc(sizeof(UDFState));
+  if(s){
+    const char * zFSI = /* signature for xFunc, xStep, xInverse */
+      "(Lorg/sqlite/jni/sqlite3_context;[Lorg/sqlite/jni/sqlite3_value;)V";
+    const char * zFV = /* signature for xFinal, xValue */
+      "(Lorg/sqlite/jni/sqlite3_context;)V";
+    memset(s, 0, sizeof(UDFState));
+    s->env = env;
+    s->jObj = REF_G(jObj);
+    s->klazz = REF_G((*env)->GetObjectClass(env, jObj));
+#define FGET(FuncName,FuncType,Field) \
+    s->Field = (*env)->GetMethodID(env, s->klazz, FuncName, FuncType); \
+    if(!s->Field) (*env)->ExceptionClear(env)
+    FGET("xFunc",    zFSI, jmidxFunc);
+    FGET("xStep",    zFSI, jmidxStep);
+    FGET("xFinal",   zFV,  jmidxFinal);
+    FGET("xValue",   zFV,  jmidxValue);
+    FGET("xInverse", zFSI, jmidxInverse);
+#undef FGET
+    if(s->jmidxFunc) s->type = UDF_SCALAR;
+    else if(s->jmidxStep && s->jmidxFinal){
+      s->type = s->jmidxValue ? UDF_WINDOW : UDF_AGGREGATE;
+    }else{
+      s->type = UDF_UNKNOWN_TYPE;
+    }
+  }
+  return s;
+}
+
+static void UDFState_free(UDFState * s){
+  JNIEnv * const env = s->env;
+  if(env){
+    //MARKER(("Collation cleanup...\n"));
+    if(s->jObj){
+      const jmethodID method =
+        (*env)->GetMethodID(env, s->klazz, "xDestroy", "()V");
+      if(method){
+        //MARKER(("aCalling SQLFunction.xDestroy()...\n"));
+        (*env)->CallVoidMethod(env, s->jObj, method);
+        EXCEPTION_IGNORE;
+        //MARKER(("Returned from SQLFunction.xDestroy().\n"));
+      }else{
+        (*env)->ExceptionClear(env);
+      }
+    }
+    UNREF_G(s->jObj);
+    UNREF_G(s->klazz);
+  }
+  sqlite3_free(s->zFuncName);
+  sqlite3_free(s);
+}
+
+static void UDFState_finalizer(void * s){
+  if(s) UDFState_free((UDFState*)s);
+}
+
+/**
+   Helper for processing args to UDF handlers
+   with signature (sqlite3_context*,int,sqlite3_value**).
+*/
+typedef struct {
+  jobject jcx;
+  jobjectArray jargv;
+} udf_jargs;
+
+static int udf_args(sqlite3_context * const cx,
+                    int argc, sqlite3_value**argv,
+                    UDFState * const s,
+                    udf_jargs * const args){
+  jobjectArray ja = 0;
+  JNIEnv * const env = s->env;
+  jobject jcx = new_sqlite3_context_wrapper(s->env, cx);
+  jint i;
+  args->jcx = 0;
+  args->jargv = 0;
+  if(!jcx) goto error_oom;
+  ja = (*(s->env))->NewObjectArray(s->env, argc,
+                                   S3Global_env_cache(env)->globalClassObj,
+                                   NULL);
+  if(!ja) goto error_oom;
+  for(i = 0; i < argc; ++i){
+    jobject jsv = new_sqlite3_value_wrapper(s->env, argv[i]);
+    if(!jsv) goto error_oom;
+    (*env)->SetObjectArrayElement(env, ja, i, jsv);
+    UNREF_L(jsv)/*array has a ref*/;
+  }
+  args->jcx = jcx;
+  args->jargv = ja;
+  return 0;
+error_oom:
+  sqlite3_result_error_nomem(cx);
+  UNREF_L(jcx);
+  UNREF_L(ja);
+  return 1;
+}
+
+static int udf_report_exception(sqlite3_context * cx, UDFState *s,
+                                const char *zFuncType){
+  int rc;
+  char * z =
+    sqlite3_mprintf("UDF %s.%s() threw. FIXME: extract "
+                    "Java-side exception message.",
+                    s->zFuncName, zFuncType);
+  if(z){
+    sqlite3_result_error(cx, z, -1);
+    sqlite3_free(z);
+    rc = SQLITE_ERROR;
+  }else{
+    rc = SQLITE_NOMEM;
+  }
+  return rc;
+}
+
+static int udf_xFSI(sqlite3_context* cx, int argc,
+                    sqlite3_value** argv,
+                    UDFState * s,
+                    jmethodID xMethodID,
+                    const char * zFuncType){
+  udf_jargs args;
+  JNIEnv * const env = s->env;
+  int rc = udf_args(cx, argc, argv, s, &args);
+  if(rc) return rc;
+  //MARKER(("UDF::%s.%s()\n", s->zFuncName, zFuncType));
+  (*env)->CallVoidMethod(env, s->jObj, xMethodID, args.jcx, args.jargv);
+  IFTHREW{
+    rc = udf_report_exception(cx,s, zFuncType);
+  }
+  UNREF_L(args.jcx);
+  UNREF_L(args.jargv);
+  return rc;
+}
+
+static int udf_xFV(sqlite3_context* cx, UDFState * s,
+                   jmethodID xMethodID,
+                   const char *zFuncType){
+  JNIEnv * const env = s->env;
+  jobject jcx = new_sqlite3_context_wrapper(s->env, cx);
+  int rc = 0;
+  if(!jcx){
+    sqlite3_result_error_nomem(cx);
+    return SQLITE_NOMEM;
+  }
+  //MARKER(("UDF::%s.%s()\n", s->zFuncName, zFuncType));
+  (*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx);
+  IFTHREW{
+    rc = udf_report_exception(cx,s, zFuncType);
+  }
+  UNREF_L(jcx);
+  return rc;
+}
+
+static void udf_xFunc(sqlite3_context* cx, int argc,
+                      sqlite3_value** argv){
+  UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  udf_xFSI(cx, argc, argv, s, s->jmidxFunc, "xFunc");
+}
+static void udf_xStep(sqlite3_context* cx, int argc,
+                      sqlite3_value** argv){
+  UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  udf_xFSI(cx, argc, argv, s, s->jmidxStep, "xStep");
+}
+static void udf_xFinal(sqlite3_context* cx){
+  UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  udf_xFV(cx, s, s->jmidxFinal, "xFinal");
+}
+static void udf_xValue(sqlite3_context* cx){
+  UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  udf_xFV(cx, s, s->jmidxValue, "xValue");
+}
+static void udf_xInverse(sqlite3_context* cx, int argc,
+                         sqlite3_value** argv){
+  UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  udf_xFSI(cx, argc, argv, s, s->jmidxInverse, "xInverse");
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// What follows is the JNI/C bindings. They are in alphabetical order
+// except for this macro-generated subset which are kept together here
+// at the front...
+////////////////////////////////////////////////////////////////////////
+WRAP_INT_DB(1errcode,                  sqlite3_errcode)
+WRAP_INT_DB(1error_1offset,            sqlite3_error_offset)
+WRAP_INT_DB(1extended_1errcode,        sqlite3_extended_errcode)
+WRAP_INT_STMT(1bind_1parameter_1count, sqlite3_bind_parameter_count)
+WRAP_INT_DB(1changes,                  sqlite3_changes)
+WRAP_INT64_DB(1changes64,              sqlite3_changes64)
+WRAP_INT_STMT(1clear_1bindings,        sqlite3_clear_bindings)
+WRAP_INT_STMT_INT(1column_1bytes,      sqlite3_column_bytes)
+WRAP_INT_STMT_INT(1column_1bytes16,    sqlite3_column_bytes16)
+WRAP_INT_STMT(1column_1count,          sqlite3_column_count)
+WRAP_STR_STMT_INT(1column_1decltype,   sqlite3_column_decltype)
+WRAP_STR_STMT_INT(1column_1name,       sqlite3_column_name)
+WRAP_STR_STMT_INT(1column_1database_1name,  sqlite3_column_database_name)
+WRAP_STR_STMT_INT(1column_1origin_1name,    sqlite3_column_origin_name)
+WRAP_STR_STMT_INT(1column_1table_1name,     sqlite3_column_table_name)
+WRAP_INT_STMT_INT(1column_1type,       sqlite3_column_type)
+WRAP_INT_STMT(1data_1count,            sqlite3_data_count)
+WRAP_MUTF8_VOID(1libversion,           sqlite3_libversion)
+WRAP_INT_VOID(1libversion_1number,     sqlite3_libversion_number)
+WRAP_INT_STMT(1reset,                  sqlite3_reset)
+WRAP_INT_INT(1sleep,                   sqlite3_sleep)
+WRAP_MUTF8_VOID(1sourceid,             sqlite3_sourceid)
+WRAP_INT_STMT(1step,                   sqlite3_step)
+WRAP_INT_VOID(1threadsafe,             sqlite3_threadsafe)
+WRAP_INT_DB(1total_1changes,           sqlite3_total_changes)
+WRAP_INT64_DB(1total_1changes64,       sqlite3_total_changes64)
+WRAP_INT_SVALUE(1value_1bytes,         sqlite3_value_bytes)
+WRAP_INT_SVALUE(1value_1bytes16,       sqlite3_value_bytes16)
+WRAP_INT_SVALUE(1value_1encoding,      sqlite3_value_encoding)
+WRAP_INT_SVALUE(1value_1frombind,      sqlite3_value_frombind)
+WRAP_INT_SVALUE(1value_1nochange,      sqlite3_value_nochange)
+WRAP_INT_SVALUE(1value_1numeric_1type, sqlite3_value_numeric_type)
+WRAP_INT_SVALUE(1value_1subtype,       sqlite3_value_subtype)
+WRAP_INT_SVALUE(1value_1type,          sqlite3_value_type)
+
+JDECL(jint,1bind_1blob)(JENV_JSELF, jobject jpStmt,
+                        jint ndx, jbyteArray baData, jint nMax){
+  int rc;
+  if(!baData){
+    rc = sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt), ndx);
+  }else{
+    jbyte * const pBuf = JBA_TOC(baData);
+    rc = sqlite3_bind_blob(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, pBuf, (int)nMax,
+                           SQLITE_TRANSIENT);
+    JBA_RELEASE(baData,pBuf);
+  }
+  return (jint)rc;
+}
+
+JDECL(jint,1bind_1double)(JENV_JSELF, jobject jpStmt,
+                         jint ndx, jdouble val){
+  return (jint)sqlite3_bind_double(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (double)val);
+}
+
+JDECL(jint,1bind_1int)(JENV_JSELF, jobject jpStmt,
+                      jint ndx, jint val){
+  return (jint)sqlite3_bind_int(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)val);
+}
+
+JDECL(jint,1bind_1int64)(JENV_JSELF, jobject jpStmt,
+                        jint ndx, jlong val){
+  return (jint)sqlite3_bind_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val);
+}
+
+JDECL(jint,1bind_1null)(JENV_JSELF, jobject jpStmt,
+                       jint ndx){
+  return (jint)sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+}
+
+JDECL(jint,1bind_1parameter_1index)(JENV_JSELF, jobject jpStmt, jbyteArray jName){
+  int rc = 0;
+  jbyte * const pBuf = JBA_TOC(jName);
+  if(pBuf){
+    rc = sqlite3_bind_parameter_index(PtrGet_sqlite3_stmt(jpStmt),
+                                      (const char *)pBuf);
+    JBA_RELEASE(jName, pBuf);
+  }
+  return rc;
+}
+
+JDECL(jint,1bind_1text)(JENV_JSELF, jobject jpStmt,
+                       jint ndx, jbyteArray baData, jint nMax){
+  if(baData){
+    jbyte * const pBuf = JBA_TOC(baData);
+    int rc = sqlite3_bind_text(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (const char *)pBuf,
+                               (int)nMax, SQLITE_TRANSIENT);
+    JBA_RELEASE(baData, pBuf);
+    return (jint)rc;
+  }else{
+    return sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+  }
+}
+
+JDECL(jint,1bind_1zeroblob)(JENV_JSELF, jobject jpStmt,
+                           jint ndx, jint n){
+  return (jint)sqlite3_bind_zeroblob(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)n);
+}
+
+JDECL(jint,1bind_1zeroblob64)(JENV_JSELF, jobject jpStmt,
+                           jint ndx, jlong n){
+  return (jint)sqlite3_bind_zeroblob(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_uint64)n);
+}
+
+JDECL(jint,1busy_1timeout)(JENV_JSELF, jobject pDb, jint ms){
+  return sqlite3_busy_timeout(PtrGet_sqlite3(pDb), (int)ms);
+}
+
+/**
+   Wrapper for sqlite3_close(_v2)().
+*/
+static jint s3jni_close_db(JNIEnv *env, jobject jDb, int version){
+  sqlite3 * pDb;
+  int rc = 0;
+  PerDbState * pS;
+  assert(version == 1 || version == 2);
+  pDb = PtrGet_sqlite3(jDb);
+  if(!pDb) return rc;
+  pS = PerDbState_for_db(env, pDb, 0);
+  rc = 1==version ? (jint)sqlite3_close(pDb) : (jint)sqlite3_close_v2(pDb);
+  if(pS) PerDbState_set_aside(pS)
+           /* MUST come after close() because of pS->trace. */;
+  setNativePointer(env, jDb, 0, ClassNames.sqlite3);
+  return (jint)rc;
+}
+
+JDECL(jint,1close_1v2)(JENV_JSELF, jobject pDb){
+  return s3jni_close_db(env, pDb, 2);
+}
+
+JDECL(jint,1close)(JENV_JSELF, jobject pDb){
+  return s3jni_close_db(env, pDb, 1);
+}
+
+JDECL(jbyteArray,1column_1blob)(JENV_JSELF, jobject jpStmt,
+                                jint ndx){
+  sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
+  void const * const p = sqlite3_column_blob(pStmt, (int)ndx);
+  int const n = p ? sqlite3_column_bytes(pStmt, (int)ndx) : 0;
+  if( 0==p ) return NULL;
+  else{
+    jbyteArray const jba = (*env)->NewByteArray(env, n);
+    (*env)->SetByteArrayRegion(env, jba, 0, n, (const jbyte *)p);
+    return jba;
+  }
+}
+
+JDECL(jdouble,1column_1double)(JENV_JSELF, jobject jpStmt,
+                               jint ndx){
+  return (jdouble)sqlite3_column_double(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+}
+
+JDECL(jint,1column_1int)(JENV_JSELF, jobject jpStmt,
+                            jint ndx){
+  return (jint)sqlite3_column_int(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+}
+
+JDECL(jlong,1column_1int64)(JENV_JSELF, jobject jpStmt,
+                            jint ndx){
+  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_text_to_jstring(JNIEnv *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 *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(jstring,1column_1text)(JENV_JSELF, 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_text_to_jstring(env, p, n);
+}
+
+JDECL(jbyteArray,1column_1text_1utf8)(JENV_JSELF, 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_JSELF, jobject jpStmt,
+                              jint ndx){
+  sqlite3_value * const sv = sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+  return new_sqlite3_value_wrapper(env, sv);
+}
+
+JDECL(jstring,1compileoption_1get)(JENV_JSELF, jint n){
+  return (*env)->NewStringUTF( env, sqlite3_compileoption_get(n) );
+}
+
+JDECL(jboolean,1compileoption_1used)(JENV_JSELF, jstring name){
+  const char *zUtf8 = (*env)->GetStringUTFChars(env, name, NULL);
+  const jboolean rc =
+    0==sqlite3_compileoption_used(zUtf8) ? JNI_FALSE : JNI_TRUE;
+  (*env)->ReleaseStringUTFChars(env, name, zUtf8);
+  return rc;
+}
+
+JDECL(jobject,1context_1db_1handle)(JENV_JSELF, jobject jpCx){
+  sqlite3 * const db = sqlite3_context_db_handle(PtrGet_sqlite3_context(jpCx));
+  return db ? new_sqlite3_wrapper(env, db) : NULL;
+}
+
+JDECL(jint,1create_1collation)(JENV_JSELF, jobject jpDb,
+                               jstring name, jint eTextRep,
+                               jobject oCollation){
+  const jclass klazz = (*env)->GetObjectClass(env, oCollation);
+  int rc;
+  const char *zName;
+  CollationState * const cs = CollationState_alloc();
+  if(!cs) return (jint)SQLITE_NOMEM;
+  cs->env = env;
+  cs->oCollation = REF_G(oCollation);
+  cs->klazz = REF_G(klazz);
+  cs->midCompare = (*env)->GetMethodID(env, klazz, "xCompare",
+                                    "([B[B)I");
+  zName = JSTR_TOC(name);
+  rc = sqlite3_create_collation_v2(PtrGet_sqlite3(jpDb), zName, (int)eTextRep,
+                                   cs, collation_xCompare_proxy,
+                                   collation_xDestroy_proxy);
+  JSTR_RELEASE(name, zName);
+  if(0 != rc) collation_xDestroy_proxy(cs);
+  return (jint)rc;
+}
+
+static jint create_function(JNIEnv * env, jobject jDb, jstring jFuncName,
+                            jint nArg, jint eTextRep, jobject jFunctor){
+  UDFState * s = 0;
+  int rc;
+  sqlite3 * const pDb = PtrGet_sqlite3(jDb);
+  const char * zFuncName = 0;
+
+  if( !encodingTypeIsValid(eTextRep) ){
+    return s3jni_db_error(pDb, SQLITE_FORMAT,
+                                "Invalid function encoding option.");
+  }
+  s = UDFState_alloc(env, jFunctor);
+  if( !s ) return SQLITE_NOMEM;
+  else if( UDF_UNKNOWN_TYPE==s->type ){
+    UDFState_free(s);
+    rc = s3jni_db_error(pDb, SQLITE_MISUSE,
+                              "Cannot unambiguously determine function type.");
+    goto error_cleanup;
+  }
+  zFuncName = JSTR_TOC(jFuncName);
+  if(!zFuncName){
+    UDFState_free(s);
+    rc = SQLITE_NOMEM;
+    goto error_cleanup;
+  }
+  if( UDF_WINDOW == s->type ){
+    rc = sqlite3_create_window_function(pDb, zFuncName, nArg, eTextRep, s,
+                                        udf_xStep, udf_xFinal, udf_xValue,
+                                        udf_xInverse, UDFState_finalizer);
+  }else{
+    udf_xFunc_f xFunc = 0;
+    udf_xStep_f xStep = 0;
+    udf_xFinal_f xFinal = 0;
+    if( UDF_SCALAR == s->type ){
+      xFunc = udf_xFunc;
+    }else{
+      assert( UDF_AGGREGATE == s->type );
+      xStep = udf_xStep;
+      xFinal = udf_xFinal;
+    }
+    rc = sqlite3_create_function_v2(pDb, zFuncName, nArg, eTextRep, s,
+                                    xFunc, xStep, xFinal,
+                                    UDFState_finalizer);
+  }
+  s->zFuncName = sqlite3_mprintf("%s", zFuncName);
+  if(!s->zFuncName){
+    rc = SQLITE_NOMEM;
+    UDFState_free(s);
+  }
+error_cleanup:
+  JSTR_RELEASE(jFuncName, zFuncName);
+  /* on create_function() error, s will be destroyed via create_function() */
+  return (jint)rc;
+}
+
+JDECL(jint,1create_1function)(JENV_JSELF, jobject jDb, jstring jFuncName,
+                              jint nArg, jint eTextRep, jobject jFunctor){
+  return create_function(env, jDb, jFuncName, nArg, eTextRep, jFunctor);
+}
+
+/*
+JDECL(jint,1create_1window_1function)(JENV_JSELF, jstring jFuncName, jint nArg,
+                                      jint eTextRep, jobject jFunctor){
+  return create_function_mega(env, jFuncName, nArg, eTextRep, jFunctor);
+}
+*/
+
+JDECL(jstring,1errmsg)(JENV_JSELF, jobject jpDb){
+  return (*env)->NewStringUTF(env, sqlite3_errmsg(PtrGet_sqlite3(jpDb)));
+}
+
+JDECL(jstring,1errstr)(JENV_JSELF, jint rcCode){
+  return (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode));
+}
+
+JDECL(jboolean,1extended_1result_1codes)(JENV_JSELF, jobject jpDb,
+                                         jboolean onoff){
+  int const rc = sqlite3_extended_result_codes(PtrGet_sqlite3(jpDb), onoff ? 1 : 0);
+  return rc ? JNI_TRUE : JNI_FALSE;
+}
+
+JDECL(jint,1initialize)(JENV_JSELF){
+  return sqlite3_initialize();
+}
+
+JDECL(jint,1finalize)(JENV_JSELF, jobject jpStmt){
+  if(jpStmt){
+    sqlite3_stmt * pStmt = PtrGet_sqlite3_stmt(jpStmt);
+    setNativePointer(env, jpStmt, 0, ClassNames.sqlite3_stmt);
+    sqlite3_finalize(pStmt);
+  }
+  return 0;
+}
+
+
+JDECL(jlong,1last_1insert_1rowid)(JENV_JSELF, jobject jpDb){
+  return (jlong)sqlite3_last_insert_rowid(PtrGet_sqlite3(jpDb));
+}
+
+
+JDECL(jint,1open)(JENV_JSELF, jstring strName, jobject ppOut){
+  sqlite3 * pOut = 0;
+  const char *zName = strName ? JSTR_TOC(strName) : 0;
+  int nrc = sqlite3_open(zName, &pOut);
+  //MARKER(("env=%p, *env=%p\n", env, *env));
+  setNativePointer(env, ppOut, pOut, ClassNames.sqlite3);
+  assert(nrc==0 ? pOut!=0 : 1);
+  JSTR_RELEASE(strName, zName);
+  return (jint)nrc;
+}
+
+JDECL(jint,1open_1v2)(JENV_JSELF, jstring strName,
+                      jobject ppOut, jint flags, jstring strVfs){
+  sqlite3 * pOut = 0;
+  const char *zName = strName ? JSTR_TOC(strName) : 0;
+  const char *zVfs = strVfs ? JSTR_TOC(strVfs) : 0;
+  int nrc = sqlite3_open_v2(zName, &pOut, (int)flags, zVfs);
+  /*MARKER(("zName=%s, zVfs=%s, pOut=%p, flags=%d, nrc=%d\n",
+    zName, zVfs, pOut, (int)flags, nrc));*/
+  setNativePointer(env, ppOut, pOut, ClassNames.sqlite3);
+  assert(nrc==0 ? pOut!=0 : 1);
+  JSTR_RELEASE(strName, zName);
+  JSTR_RELEASE(strVfs, zVfs);
+  return (jint)nrc;
+}
+
+/* Proxy for the sqlite3_prepare[_v2/3]() family. */
+static jint sqlite3_jni_prepare_v123(int prepVersion, JNIEnv *env, jclass self,
+                                     jobject jpDb, jbyteArray baSql,
+                                     jint nMax, jint prepFlags,
+                                     jobject outStmt, jobject outTail){
+  sqlite3_stmt * pStmt = 0;
+  const char * zTail = 0;
+  jbyte * const pBuf = JBA_TOC(baSql);
+  int rc = SQLITE_ERROR;
+  assert(prepVersion==1 || prepVersion==2 || prepVersion==3);
+  switch( prepVersion ){
+    case 1: rc = sqlite3_prepare(PtrGet_sqlite3(jpDb), (const char *)pBuf,
+                                 (int)nMax, &pStmt, &zTail);
+      break;
+    case 2: rc = sqlite3_prepare_v2(PtrGet_sqlite3(jpDb), (const char *)pBuf,
+                                    (int)nMax, &pStmt, &zTail);
+      break;
+    case 3: rc = sqlite3_prepare_v3(PtrGet_sqlite3(jpDb), (const char *)pBuf,
+                                    (int)nMax, (unsigned int)prepFlags,
+                                    &pStmt, &zTail);
+      break;
+    default:
+      assert(0 && "Invalid prepare() version");
+  }
+  JBA_RELEASE(baSql,pBuf);
+  if( 0!=outTail ){
+    assert(zTail ? ((void*)zTail>=(void*)pBuf) : 1);
+    assert(zTail ? (((int)((void*)zTail - (void*)pBuf)) >= 0) : 1);
+    setOutputInt32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
+  }
+  setNativePointer(env, outStmt, pStmt, ClassNames.sqlite3_stmt);
+  return (jint)rc;
+}
+JDECL(jint,1prepare)(JNIEnv *env, jclass self, jobject jpDb, jbyteArray baSql,
+                     jint nMax, jobject outStmt, jobject outTail){
+  return sqlite3_jni_prepare_v123(1, env, self, jpDb, baSql, nMax, 0,
+                                  outStmt, outTail);
+}
+JDECL(jint,1prepare_1v2)(JNIEnv *env, jclass self, jobject jpDb, jbyteArray baSql,
+                         jint nMax, jobject outStmt, jobject outTail){
+  return sqlite3_jni_prepare_v123(2, env, self, jpDb, baSql, nMax, 0,
+                                  outStmt, outTail);
+}
+JDECL(jint,1prepare_1v3)(JNIEnv *env, jclass self, jobject jpDb, jbyteArray baSql,
+                         jint nMax, jint prepFlags, jobject outStmt, jobject outTail){
+  return sqlite3_jni_prepare_v123(3, env, self, jpDb, baSql, nMax,
+                                  prepFlags, outStmt, outTail);
+}
+
+/* sqlite3_result_text/blob() and friends. */
+static void result_blob_text(int asBlob, int as64,
+                             int eTextRep/*only for (asBlob=0)*/,
+                             JNIEnv *env, sqlite3_context *pCx,
+                             jbyteArray jBa, jlong nMax){
+  if(jBa){
+    jbyte * const pBuf = JBA_TOC(jBa);
+    jsize nBa = (*env)->GetArrayLength(env, jBa);
+    if( nMax>=0 && nBa>(jsize)nMax ){
+      nBa = (jsize)nMax;
+      /**
+         From the sqlite docs:
+
+         > If the 3rd parameter to any of the sqlite3_result_text*
+           interfaces other than sqlite3_result_text64() is negative,
+           then SQLite computes the string length itself by searching
+           the 2nd parameter for the first zero character.
+
+         Note that the text64() interfaces take an unsigned value for
+         the length, which Java does not support. This binding takes
+         the approach of passing on negative values to the C API,
+         which will, in turn fail with SQLITE_TOOBIG at some later
+         point (recall that the sqlite3_result_xyz() family do not
+         have result values).
+      */
+    }
+    if(as64){ /* 64-bit... */
+      static const jsize nLimit64 =
+        SQLITE_MAX_ALLOCATION_SIZE/*only _kinda_ arbitrary!*/
+        /* jsize is int32, not int64! */;
+      if(nBa > nLimit64){
+        sqlite3_result_error_toobig(pCx);
+      }else if(asBlob){
+        sqlite3_result_blob64(pCx, pBuf, (sqlite3_uint64)nBa,
+                              SQLITE_TRANSIENT);
+      }else{ /* text64... */
+        if(encodingTypeIsValid(eTextRep)){
+          sqlite3_result_text64(pCx, (const char *)pBuf,
+                                (sqlite3_uint64)nBa,
+                                SQLITE_TRANSIENT, eTextRep);
+        }else{
+          sqlite3_result_error_code(pCx, SQLITE_FORMAT);
+        }
+      }
+    }else{ /* 32-bit... */
+      static const jsize nLimit = SQLITE_MAX_ALLOCATION_SIZE;
+      if(nBa > nLimit){
+        sqlite3_result_error_toobig(pCx);
+      }else if(asBlob){
+        sqlite3_result_blob(pCx, pBuf, (int)nBa,
+                            SQLITE_TRANSIENT);
+      }else{
+        switch(eTextRep){
+          case SQLITE_UTF8:
+            sqlite3_result_text(pCx, (const char *)pBuf, (int)nBa,
+                                SQLITE_TRANSIENT);
+            break;
+          case SQLITE_UTF16:
+            sqlite3_result_text16(pCx, (const char *)pBuf, (int)nBa,
+                                  SQLITE_TRANSIENT);
+            break;
+          case SQLITE_UTF16LE:
+            sqlite3_result_text16le(pCx, (const char *)pBuf, (int)nBa,
+                                    SQLITE_TRANSIENT);
+            break;
+          case SQLITE_UTF16BE:
+            sqlite3_result_text16be(pCx, (const char *)pBuf, (int)nBa,
+                                    SQLITE_TRANSIENT);
+            break;
+        }
+      }
+      JBA_RELEASE(jBa, pBuf);
+    }
+  }else{
+    sqlite3_result_null(pCx);
+  }
+}
+
+JDECL(void,1result_1blob)(JENV_JSELF, jobject jpCx, jbyteArray jBa, jint nMax){
+  return result_blob_text(1, 0, 0, env, PtrGet_sqlite3_context(jpCx), jBa, nMax);
+}
+
+JDECL(void,1result_1blob64)(JENV_JSELF, jobject jpCx, jbyteArray jBa, jlong nMax){
+  return result_blob_text(1, 1, 0, env, PtrGet_sqlite3_context(jpCx), jBa, nMax);
+}
+
+JDECL(void,1result_1double)(JENV_JSELF, jobject jpCx, jdouble v){
+  sqlite3_result_double(PtrGet_sqlite3_context(jpCx), v);
+}
+
+JDECL(void,1result_1error)(JENV_JSELF, jobject jpCx, jbyteArray baMsg,
+                           int eTextRep){
+  const char * zUnspecified = "Unspecified error.";
+  jsize const baLen = (*env)->GetArrayLength(env, baMsg);
+  jbyte * const pjBuf = baMsg ? JBA_TOC(baMsg) : NULL;
+  switch(pjBuf ? eTextRep : SQLITE_UTF8){
+    case SQLITE_UTF8: {
+      const char *zMsg = pjBuf ? (const char *)pjBuf : zUnspecified;
+      sqlite3_result_error(PtrGet_sqlite3_context(jpCx), zMsg, baLen);
+      break;
+    }
+    case SQLITE_UTF16: {
+      const void *zMsg = pjBuf
+        ? (const void *)pjBuf : (const void *)zUnspecified;
+      sqlite3_result_error16(PtrGet_sqlite3_context(jpCx), zMsg, baLen);
+      break;
+    }
+    default:
+      sqlite3_result_error(PtrGet_sqlite3_context(jpCx),
+                           "Invalid encoding argument passed "
+                           "to sqlite3_result_error().", -1);
+      break;
+  }
+  JBA_RELEASE(baMsg,pjBuf);
+}
+
+JDECL(void,1result_1error_1code)(JENV_JSELF, jobject jpCx, jint v){
+  sqlite3_result_error_code(PtrGet_sqlite3_context(jpCx), v ? (int)v : SQLITE_ERROR);
+}
+
+JDECL(void,1result_1error_1nomem)(JENV_JSELF, jobject jpCx){
+  sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx));
+}
+
+JDECL(void,1result_1error_1toobig)(JENV_JSELF, jobject jpCx){
+  sqlite3_result_error_toobig(PtrGet_sqlite3_context(jpCx));
+}
+
+JDECL(void,1result_1int)(JENV_JSELF, jobject jpCx, jint v){
+  sqlite3_result_int(PtrGet_sqlite3_context(jpCx), (int)v);
+}
+
+JDECL(void,1result_1int64)(JENV_JSELF, jobject jpCx, jlong v){
+  sqlite3_result_int64(PtrGet_sqlite3_context(jpCx), (sqlite3_int64)v);
+}
+
+JDECL(void,1result_1java_1object)(JENV_JSELF, jobject jpCx, jobject v){
+  if(v){
+    ResultJavaVal * const rjv = ResultJavaVal_alloc(env, v);
+    if(rjv){
+      sqlite3_result_pointer(PtrGet_sqlite3_context(jpCx), rjv, RESULT_JAVA_VAL_STRING,
+                             ResultJavaVal_finalizer);
+    }else{
+      sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx));
+    }
+  }else{
+    sqlite3_result_null(PtrGet_sqlite3_context(jpCx));
+  }
+}
+
+JDECL(void,1result_1null)(JENV_JSELF, jobject jpCx){
+  sqlite3_result_null(PtrGet_sqlite3_context(jpCx));
+}
+
+JDECL(void,1result_1text)(JENV_JSELF, jobject jpCx, jbyteArray jBa, jint nMax){
+  return result_blob_text(0, 0, SQLITE_UTF8, env, PtrGet_sqlite3_context(jpCx), jBa, nMax);
+}
+
+JDECL(void,1result_1text64)(JENV_JSELF, jobject jpCx, jbyteArray jBa, jlong nMax,
+                            jint eTextRep){
+  return result_blob_text(0, 1, eTextRep, env, PtrGet_sqlite3_context(jpCx), jBa, nMax);
+}
+
+JDECL(void,1result_1value)(JENV_JSELF, jobject jpCx, jobject jpSVal){
+  sqlite3_result_value(PtrGet_sqlite3_context(jpCx), PtrGet_sqlite3_value(jpSVal));
+}
+
+JDECL(void,1result_1zeroblob)(JENV_JSELF, jobject jpCx, jint v){
+  sqlite3_result_zeroblob(PtrGet_sqlite3_context(jpCx), (int)v);
+}
+
+JDECL(jint,1result_1zeroblob64)(JENV_JSELF, jobject jpCx, jlong v){
+  return (jint)sqlite3_result_zeroblob64(PtrGet_sqlite3_context(jpCx), (sqlite3_int64)v);
+}
+
+
+JDECL(void,1set_1last_1insert_1rowid)(JENV_JSELF, jobject jpDb, jlong rowId){
+  sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb),
+                                (sqlite3_int64)rowId);
+}
+
+JDECL(jint,1shutdown)(JENV_JSELF){
+  PerDbState_free_all();
+  JNIEnvCache_clear(&S3Global.envCache);
+  /* Do not clear S3Global.jvm: it's legal to call
+     sqlite3_initialize() again to restart the lib. */
+  return sqlite3_shutdown();
+}
+
+static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
+  PerDbState * const ps = (PerDbState *)pC;
+  JNIEnv * const env = ps->env;
+  jobject jX = NULL;
+  JNIEnvCacheLine * const pEcl = S3Global_env_cache(env);
+  int rc;
+  /**
+     TODO: convert pX depending on traceflag:
+
+     SQLITE_TRACE_STMT: String
+     SQLITE_TRACE_PROFILE: Long
+     others: null
+  */
+  switch(traceflag){
+  case SQLITE_TRACE_STMT:
+    /* This is not _quite_ right: we're converting to MUTF-8.  It
+       should(?) suffice for purposes of tracing, though. */
+    jX = (*env)->NewStringUTF(env, (const char *)pX);
+    break;
+  case SQLITE_TRACE_PROFILE:
+    jX = (*env)->NewObject(env, pEcl->globalClassLong, pEcl->ctorLong1,
+                           (jlong)*((sqlite3_int64*)pX));
+    break;
+  }
+  rc = (int)(*env)->CallIntMethod(env, ps->trace.jObj,
+                                  ps->trace.midCallback,
+                                  (jint)traceflag, (jlong)pP, jX);
+  UNREF_L(jX);
+  IFTHREW{
+    EXCEPTION_CLEAR;
+    return rc ? rc :
+      s3jni_db_error(ps->pDb, SQLITE_ERROR,
+                     "sqlite3_trace_v2() callback threw.");
+  }
+  return rc;
+}
+
+JDECL(jint,1trace_1v2)(JENV_JSELF,jobject jDb, jint traceMask, jobject jTracer){
+  sqlite3 * const pDb = PtrGet_sqlite3(jDb);
+  PerDbState * ps;
+  jclass klazz;
+  if( !traceMask || !jTracer ){
+    return (jint)sqlite3_trace_v2(pDb, 0, 0, 0);
+  }
+  ps = PerDbState_for_db(env, pDb, 1);
+  if(!ps) return SQLITE_NOMEM;
+  klazz = (*env)->GetObjectClass(env, jTracer);
+  ps->trace.midCallback = (*env)->GetMethodID(env, klazz, "xCallback",
+                                              "(IJLjava/lang/Object;)I");
+  IFTHREW {
+    /* Leave ps in place - it might contain other state. */
+    EXCEPTION_CLEAR;
+    return s3jni_db_error(pDb, SQLITE_ERROR,
+                          "Cannot not find matchin xCallback() on Tracer object.");
+  }
+  ps->trace.jObj = REF_G(jTracer);
+  return sqlite3_trace_v2(pDb, (unsigned)traceMask, s3jni_trace_impl, ps);
+}
+
+
+JDECL(jbyteArray,1value_1blob)(JENV_JSELF, jobject jpSVal){
+  sqlite3_value * const sv = PtrGet_sqlite3_value(jpSVal);
+  int const nLen = sqlite3_value_bytes(sv);
+  const jbyte * pBytes = sqlite3_value_blob(sv);
+  jbyteArray const jba = pBytes
+    ? (*env)->NewByteArray(env, (jsize)nLen)
+    : NULL;
+  if(jba){
+    (*env)->SetByteArrayRegion(env, jba, 0, nLen, pBytes);
+  }
+  return jba;
+}
+
+
+JDECL(jdouble,1value_1double)(JENV_JSELF, jobject jpSVal){
+  return (jdouble) sqlite3_value_double(PtrGet_sqlite3_value(jpSVal));
+}
+
+
+JDECL(jobject,1value_1dup)(JENV_JSELF, jobject jpSVal){
+  sqlite3_value * const sv = sqlite3_value_dup(PtrGet_sqlite3_value(jpSVal));
+  return sv ? new_sqlite3_value_wrapper(env, sv) : 0;
+}
+
+JDECL(void,1value_1free)(JENV_JSELF, jobject jpSVal){
+  sqlite3_value_free(PtrGet_sqlite3_value(jpSVal));
+}
+
+JDECL(jint,1value_1int)(JENV_JSELF, jobject jpSVal){
+  return (jint) sqlite3_value_int(PtrGet_sqlite3_value(jpSVal));
+}
+
+JDECL(jlong,1value_1int64)(JENV_JSELF, jobject jpSVal){
+  return (jlong) sqlite3_value_int64(PtrGet_sqlite3_value(jpSVal));
+}
+
+JDECL(jobject,1value_1java_1object)(JENV_JSELF, jobject jpSVal){
+  ResultJavaVal * const rv = sqlite3_value_pointer(PtrGet_sqlite3_value(jpSVal), RESULT_JAVA_VAL_STRING);
+  return rv ? rv->jObj : NULL;
+}
+
+JDECL(jstring,1value_1text)(JENV_JSELF, jobject jpSVal){
+  sqlite3_value * const sv = PtrGet_sqlite3_value(jpSVal);
+  int const n = sqlite3_value_bytes16(sv);
+  const void * const p = sqlite3_value_text16(sv);
+  return s3jni_text_to_jstring(env, p, n);
+}
+
+JDECL(jbyteArray,1value_1text_1utf8)(JENV_JSELF, jobject jpSVal){
+  sqlite3_value * const sv = PtrGet_sqlite3_value(jpSVal);
+  int const n = sqlite3_value_bytes(sv);
+  const unsigned char * const p = sqlite3_value_text(sv);
+  return s3jni_new_jbyteArray(env, p, n);
+}
+
+static jbyteArray value_text16(int mode, JNIEnv *env, jobject jpSVal){
+  int const nLen = sqlite3_value_bytes16(PtrGet_sqlite3_value(jpSVal));
+  jbyteArray jba;
+  const jbyte * pBytes;
+  switch(mode){
+    case SQLITE_UTF16:
+      pBytes = sqlite3_value_text16(PtrGet_sqlite3_value(jpSVal));
+      break;
+    case SQLITE_UTF16LE:
+      pBytes = sqlite3_value_text16le(PtrGet_sqlite3_value(jpSVal));
+      break;
+    case SQLITE_UTF16BE:
+      pBytes = sqlite3_value_text16be(PtrGet_sqlite3_value(jpSVal));
+      break;
+    default:
+      assert(!"not possible");
+      return NULL;
+  }
+  jba = pBytes
+    ? (*env)->NewByteArray(env, (jsize)nLen)
+    : NULL;
+  if(jba){
+    (*env)->SetByteArrayRegion(env, jba, 0, nLen, pBytes);
+  }
+  return jba;
+}
+
+JDECL(jbyteArray,1value_1text16)(JENV_JSELF, jobject jpSVal){
+  return value_text16(SQLITE_UTF16, env, jpSVal);
+}
+
+JDECL(jbyteArray,1value_1text16le)(JENV_JSELF, jobject jpSVal){
+  return value_text16(SQLITE_UTF16LE, env, jpSVal);
+}
+
+JDECL(jbyteArray,1value_1text16be)(JENV_JSELF, jobject jpSVal){
+  return value_text16(SQLITE_UTF16BE, env, jpSVal);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// End of the main API bindings. What follows are internal utilities.
+////////////////////////////////////////////////////////////////////////
+
+/**
+   Called during static init of the SQLite3Jni class to sync certain
+   compile-time constants to Java-space.
+
+   This routine is why we have to #include sqlite3.c instead of
+   sqlite3.h.
+*/
+JNIEXPORT void JNICALL
+Java_org_sqlite_jni_SQLite3Jni_init(JNIEnv *env, jclass self, jobject sJni){
+  typedef struct {
+    const char *zName;
+    int value;
+  } LimitEntry;
+  const LimitEntry aLimits[] = {
+    {"SQLITE_MAX_ALLOCATION_SIZE", SQLITE_MAX_ALLOCATION_SIZE},
+    {"SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH},
+    {"SQLITE_MAX_LENGTH", SQLITE_MAX_LENGTH},
+    {"SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH},
+    {"SQLITE_MAX_SQL_LENGTH", SQLITE_MAX_SQL_LENGTH},
+    {"SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN},
+    {"SQLITE_MAX_COLUMN", SQLITE_MAX_COLUMN},
+    {"SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH},
+    {"SQLITE_MAX_EXPR_DEPTH", SQLITE_MAX_EXPR_DEPTH},
+    {"SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT},
+    {"SQLITE_MAX_COMPOUND_SELECT", SQLITE_MAX_COMPOUND_SELECT},
+    {"SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP},
+    {"SQLITE_MAX_VDBE_OP", SQLITE_MAX_VDBE_OP},
+    {"SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG},
+    {"SQLITE_MAX_FUNCTION_ARG", SQLITE_MAX_FUNCTION_ARG},
+    {"SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED},
+    {"SQLITE_MAX_ATTACHED", SQLITE_MAX_ATTACHED},
+    {"SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH},
+    {"SQLITE_MAX_LIKE_PATTERN_LENGTH", SQLITE_MAX_LIKE_PATTERN_LENGTH},
+    {"SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER},
+    {"SQLITE_MAX_VARIABLE_NUMBER", SQLITE_MAX_VARIABLE_NUMBER},
+    {"SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH},
+    {"SQLITE_MAX_TRIGGER_DEPTH", SQLITE_MAX_TRIGGER_DEPTH},
+    {"SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS},
+    {"SQLITE_MAX_WORKER_THREADS", SQLITE_MAX_WORKER_THREADS},
+    {0,0}
+  };
+  jfieldID fieldId;
+  jclass const klazz = (*env)->GetObjectClass(env, sJni);
+  const LimitEntry * pLimit;
+  memset(&S3Global, 0, sizeof(S3Global));
+  (void)S3Global_env_cache(env);
+  assert( 1 == S3Global.envCache.used );
+  assert( env == S3Global.envCache.lines[0].env );
+  assert( 0 != S3Global.envCache.lines[0].globalClassObj );
+  if( (*env)->GetJavaVM(env, &S3Global.jvm) ){
+    (*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible.");
+  }
+
+  for( pLimit = &aLimits[0]; pLimit->zName; ++pLimit ){
+    fieldId = (*env)->GetStaticFieldID(env, klazz, pLimit->zName, "I");
+    //MARKER(("Setting %s (field=%p) = %d\n", pLimit->zName, fieldId, pLimit->value));
+    assert(fieldId);
+    (*env)->SetStaticIntField(env, klazz, fieldId, (jint)pLimit->value);
+  }
+}
diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h
new file mode 100644 (file)
index 0000000..a55d437
--- /dev/null
@@ -0,0 +1,1561 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_sqlite_jni_SQLite3Jni */
+
+#ifndef _Included_org_sqlite_jni_SQLite3Jni
+#define _Included_org_sqlite_jni_SQLite3Jni
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_EXISTS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_EXISTS 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_READWRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_READWRITE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_READ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ACCESS_READ 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DENY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DENY 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IGNORE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IGNORE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_INDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_INDEX 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TABLE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_INDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_INDEX 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_TABLE 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_TRIGGER 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_VIEW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TEMP_VIEW 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_TRIGGER 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_VIEW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_VIEW 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DELETE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DELETE 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_INDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_INDEX 10L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TABLE 11L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_INDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_INDEX 12L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_TABLE 13L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_TRIGGER 14L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_VIEW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TEMP_VIEW 15L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_TRIGGER 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_VIEW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_VIEW 17L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INSERT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INSERT 18L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PRAGMA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PRAGMA 19L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READ 20L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SELECT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SELECT 21L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRANSACTION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRANSACTION 22L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UPDATE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UPDATE 23L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ATTACH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ATTACH 24L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DETACH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DETACH 25L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ALTER_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ALTER_TABLE 26L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_REINDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_REINDEX 27L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ANALYZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ANALYZE 28L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_VTABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CREATE_VTABLE 29L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DROP_VTABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DROP_VTABLE 30L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FUNCTION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FUNCTION 31L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SAVEPOINT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SAVEPOINT 32L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_RECURSIVE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_RECURSIVE 33L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATIC 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRANSIENT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRANSIENT -1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETSTART_INVERT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETSTART_INVERT 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_NOSAVEPOINT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_NOSAVEPOINT 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_INVERT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_INVERT 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_IGNORENOOP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESETAPPLY_IGNORENOOP 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_DATA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_DATA 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_NOTFOUND
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_NOTFOUND 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_CONFLICT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_CONFLICT 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_CONSTRAINT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_CONSTRAINT 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_FOREIGN_KEY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_FOREIGN_KEY 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_OMIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_OMIT 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_REPLACE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_REPLACE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_ABORT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CHANGESET_ABORT 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SINGLETHREAD
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SINGLETHREAD 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MULTITHREAD
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MULTITHREAD 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SERIALIZED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SERIALIZED 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MALLOC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MALLOC 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETMALLOC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETMALLOC 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SCRATCH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SCRATCH 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PAGECACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PAGECACHE 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_HEAP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_HEAP 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MEMSTATUS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MEMSTATUS 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MUTEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MUTEX 10L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETMUTEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETMUTEX 11L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_LOOKASIDE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_LOOKASIDE 13L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE 14L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETPCACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETPCACHE 15L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_LOG
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_LOG 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_URI
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_URI 17L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE2
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE2 18L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETPCACHE2
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_GETPCACHE2 19L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_COVERING_INDEX_SCAN
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_COVERING_INDEX_SCAN 20L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SQLLOG
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SQLLOG 21L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MMAP_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MMAP_SIZE 22L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_WIN32_HEAPSIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_WIN32_HEAPSIZE 23L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE_HDRSZ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PCACHE_HDRSZ 24L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PMASZ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_PMASZ 25L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_STMTJRNL_SPILL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_STMTJRNL_SPILL 26L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SMALL_MALLOC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SMALL_MALLOC 27L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SORTERREF_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_SORTERREF_SIZE 28L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MEMDB_MAXSIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONFIG_MEMDB_MAXSIZE 29L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INTEGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INTEGER 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FLOAT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FLOAT 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TEXT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TEXT 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_BLOB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_BLOB 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NULL 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_MAINDBNAME
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_MAINDBNAME 1000L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LOOKASIDE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LOOKASIDE 1001L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_FKEY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_FKEY 1002L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_TRIGGER 1003L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_QPSG
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_QPSG 1007L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_TRIGGER_EQP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_TRIGGER_EQP 1008L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_RESET_DATABASE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_RESET_DATABASE 1009L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DEFENSIVE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DEFENSIVE 1010L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_WRITABLE_SCHEMA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DQS_DML
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DQS_DML 1013L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DQS_DDL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_DQS_DDL 1014L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_VIEW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_ENABLE_VIEW 1015L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_TRUSTED_SCHEMA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_STMT_SCANSTATUS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_STMT_SCANSTATUS 1018L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_REVERSE_SCANORDER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_REVERSE_SCANORDER 1019L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_MAX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBCONFIG_MAX 1019L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_USED 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_USED 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_SCHEMA_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_SCHEMA_USED 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_STMT_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_STMT_USED 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_HIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_HIT 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_HIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_HIT 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_MISS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_MISS 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_WRITE 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_DEFERRED_FKS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_DEFERRED_FKS 10L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_USED_SHARED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_USED_SHARED 11L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_SPILL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_CACHE_SPILL 12L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_MAX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DBSTATUS_MAX 12L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UTF8
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UTF8 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UTF16LE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UTF16LE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UTF16BE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UTF16BE 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UTF16
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UTF16 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_UTF16_ALIGNED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_UTF16_ALIGNED 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LOCKSTATE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LOCKSTATE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_GET_LOCKPROXYFILE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_GET_LOCKPROXYFILE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SET_LOCKPROXYFILE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SET_LOCKPROXYFILE 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LAST_ERRNO
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LAST_ERRNO 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SIZE_HINT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SIZE_HINT 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CHUNK_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CHUNK_SIZE 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_FILE_POINTER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_FILE_POINTER 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SYNC_OMITTED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SYNC_OMITTED 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_AV_RETRY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_AV_RETRY 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PERSIST_WAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PERSIST_WAL 10L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_OVERWRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_OVERWRITE 11L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_VFSNAME
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_VFSNAME 12L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_POWERSAFE_OVERWRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_POWERSAFE_OVERWRITE 13L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PRAGMA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PRAGMA 14L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_BUSYHANDLER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_BUSYHANDLER 15L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_TEMPFILENAME
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_TEMPFILENAME 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_MMAP_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_MMAP_SIZE 18L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_TRACE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_TRACE 19L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_HAS_MOVED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_HAS_MOVED 20L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SYNC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SYNC 21L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_COMMIT_PHASETWO
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_COMMIT_PHASETWO 22L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_SET_HANDLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_SET_HANDLE 23L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WAL_BLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WAL_BLOCK 24L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_ZIPVFS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_ZIPVFS 25L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RBU
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RBU 26L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_VFS_POINTER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_VFS_POINTER 27L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_JOURNAL_POINTER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_JOURNAL_POINTER 28L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_GET_HANDLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_WIN32_GET_HANDLE 29L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PDB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_PDB 30L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_BEGIN_ATOMIC_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_COMMIT_ATOMIC_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LOCK_TIMEOUT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_LOCK_TIMEOUT 34L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_DATA_VERSION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_DATA_VERSION 35L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SIZE_LIMIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_SIZE_LIMIT 36L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKPT_DONE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKPT_DONE 37L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RESERVE_BYTES
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RESERVE_BYTES 38L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKPT_START
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKPT_START 39L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_EXTERNAL_READER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_EXTERNAL_READER 40L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKSM_FILE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_CKSM_FILE 41L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RESET_CACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FCNTL_RESET_CACHE 42L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_NONE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_NONE 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_SHARED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_SHARED 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_RESERVED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_RESERVED 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_PENDING
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_PENDING 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_EXCLUSIVE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCK_EXCLUSIVE 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC512
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC512 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC1K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC1K 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC2K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC2K 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC4K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC4K 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC8K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC8K 32L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC16K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC16K 64L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC32K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC32K 128L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC64K
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_ATOMIC64K 256L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_SAFE_APPEND
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_SAFE_APPEND 512L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_SEQUENTIAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_SEQUENTIAL 1024L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 2048L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_POWERSAFE_OVERWRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_POWERSAFE_OVERWRITE 4096L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_IMMUTABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_IMMUTABLE 8192L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_BATCH_ATOMIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOCAP_BATCH_ATOMIC 16384L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_READONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_READONLY 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_READWRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_READWRITE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_CREATE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_CREATE 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_URI
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_URI 64L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MEMORY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MEMORY 128L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_NOMUTEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_NOMUTEX 32768L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_FULLMUTEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_FULLMUTEX 65536L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SHAREDCACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SHAREDCACHE 131072L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_PRIVATECACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_PRIVATECACHE 262144L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_EXRESCODE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_EXRESCODE 33554432L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_NOFOLLOW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_NOFOLLOW 16777216L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MAIN_DB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MAIN_DB 256L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MAIN_JOURNAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_MAIN_JOURNAL 2048L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TEMP_DB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TEMP_DB 512L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TEMP_JOURNAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TEMP_JOURNAL 4096L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TRANSIENT_DB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_TRANSIENT_DB 1024L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SUBJOURNAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SUBJOURNAL 8192L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SUPER_JOURNAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_SUPER_JOURNAL 16384L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_WAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_WAL 524288L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_DELETEONCLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_DELETEONCLOSE 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_EXCLUSIVE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OPEN_EXCLUSIVE 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_PERSISTENT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_PERSISTENT 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_NORMALIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_NORMALIZE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_NO_VTAB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PREPARE_NO_VTAB 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OK 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ERROR
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ERROR 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INTERNAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INTERNAL 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PERM
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PERM 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ABORT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ABORT 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_BUSY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_BUSY 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOMEM
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOMEM 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INTERRUPT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INTERRUPT 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR 10L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT 11L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOTFOUND
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOTFOUND 12L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FULL 13L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN 14L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_PROTOCOL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_PROTOCOL 15L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_EMPTY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_EMPTY 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SCHEMA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SCHEMA 17L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TOOBIG
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TOOBIG 18L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT 19L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_MISMATCH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_MISMATCH 20L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_MISUSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_MISUSE 21L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOLFS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOLFS 22L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_AUTH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_AUTH 23L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FORMAT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FORMAT 24L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_RANGE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_RANGE 25L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOTADB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOTADB 26L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE 27L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_WARNING
+#define org_sqlite_jni_SQLite3Jni_SQLITE_WARNING 28L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ROW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ROW 100L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DONE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DONE 101L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_MISSING_COLLSEQ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_MISSING_COLLSEQ 257L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_RETRY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_RETRY 513L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_SNAPSHOT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ERROR_SNAPSHOT 769L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_READ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_READ 266L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHORT_READ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHORT_READ 522L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_WRITE 778L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_FSYNC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_FSYNC 1034L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DIR_FSYNC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DIR_FSYNC 1290L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_TRUNCATE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_TRUNCATE 1546L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_FSTAT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_FSTAT 1802L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_UNLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_UNLOCK 2058L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_RDLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_RDLOCK 2314L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DELETE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DELETE 2570L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_BLOCKED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_BLOCKED 2826L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_NOMEM
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_NOMEM 3082L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_ACCESS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_ACCESS 3338L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CHECKRESERVEDLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CHECKRESERVEDLOCK 3594L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_LOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_LOCK 3850L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CLOSE 4106L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DIR_CLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DIR_CLOSE 4362L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMOPEN
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMOPEN 4618L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMSIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMSIZE 4874L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMLOCK 5130L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMMAP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SHMMAP 5386L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SEEK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_SEEK 5642L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DELETE_NOENT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DELETE_NOENT 5898L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_MMAP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_MMAP 6154L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_GETTEMPPATH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_GETTEMPPATH 6410L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CONVPATH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CONVPATH 6666L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_VNODE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_VNODE 6922L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_AUTH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_AUTH 7178L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_BEGIN_ATOMIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_BEGIN_ATOMIC 7434L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_COMMIT_ATOMIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_COMMIT_ATOMIC 7690L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_ROLLBACK_ATOMIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_ROLLBACK_ATOMIC 7946L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DATA
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_DATA 8202L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CORRUPTFS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_IOERR_CORRUPTFS 8458L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED_SHAREDCACHE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED_SHAREDCACHE 262L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED_VTAB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_LOCKED_VTAB 518L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_RECOVERY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_RECOVERY 261L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_SNAPSHOT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_SNAPSHOT 517L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_TIMEOUT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_BUSY_TIMEOUT 773L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_NOTEMPDIR
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_NOTEMPDIR 270L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_ISDIR
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_ISDIR 526L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_FULLPATH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_FULLPATH 782L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_CONVPATH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_CONVPATH 1038L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_SYMLINK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CANTOPEN_SYMLINK 1550L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_VTAB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_VTAB 267L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_SEQUENCE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_SEQUENCE 523L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_INDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CORRUPT_INDEX 779L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_RECOVERY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_RECOVERY 264L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_CANTLOCK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_CANTLOCK 520L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_ROLLBACK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_ROLLBACK 776L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_DBMOVED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_DBMOVED 1032L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_CANTINIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_CANTINIT 1288L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_DIRECTORY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_READONLY_DIRECTORY 1544L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ABORT_ROLLBACK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ABORT_ROLLBACK 516L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_CHECK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_CHECK 275L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_COMMITHOOK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_COMMITHOOK 531L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_FOREIGNKEY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_FOREIGNKEY 787L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_FUNCTION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_FUNCTION 1043L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_NOTNULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_NOTNULL 1299L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_PRIMARYKEY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_PRIMARYKEY 1555L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_TRIGGER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_TRIGGER 1811L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_UNIQUE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_UNIQUE 2067L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_VTAB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_VTAB 2323L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_ROWID
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_ROWID 2579L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_PINNED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_PINNED 2835L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_DATATYPE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_CONSTRAINT_DATATYPE 3091L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE_RECOVER_WAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE_RECOVER_WAL 283L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE_RECOVER_ROLLBACK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_NOTICE_RECOVER_ROLLBACK 539L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_WARNING_AUTOINDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_WARNING_AUTOINDEX 284L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_AUTH_USER
+#define org_sqlite_jni_SQLite3Jni_SQLITE_AUTH_USER 279L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_OK_LOAD_PERMANENTLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_OK_LOAD_PERMANENTLY 256L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SERIALIZE_NOCOPY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SERIALIZE_NOCOPY 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_FREEONCLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_FREEONCLOSE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_READONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_READONLY 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_RESIZEABLE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DESERIALIZE_RESIZEABLE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SESSION_CONFIG_STRMSIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SESSION_CONFIG_STRMSIZE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SESSION_OBJCONFIG_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SESSION_OBJCONFIG_SIZE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MEMORY_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MEMORY_USED 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_USED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_USED 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_OVERFLOW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_OVERFLOW 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MALLOC_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MALLOC_SIZE 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PARSER_STACK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PARSER_STACK 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_SIZE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_PAGECACHE_SIZE 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MALLOC_COUNT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STATUS_MALLOC_COUNT 9L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FULLSCAN_STEP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FULLSCAN_STEP 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_SORT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_SORT 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_AUTOINDEX
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_AUTOINDEX 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_VM_STEP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_VM_STEP 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_REPREPARE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_REPREPARE 5L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_RUN
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_RUN 6L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FILTER_MISS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FILTER_MISS 7L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FILTER_HIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_FILTER_HIT 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_MEMUSED
+#define org_sqlite_jni_SQLite3Jni_SQLITE_STMTSTATUS_MEMUSED 99L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_NORMAL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_NORMAL 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_FULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_FULL 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_DATAONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_SYNC_DATAONLY 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_STMT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_STMT 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_PROFILE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_PROFILE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_ROW
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_ROW 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_CLOSE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TRACE_CLOSE 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TXN_NONE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TXN_NONE 0L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TXN_READ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TXN_READ 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_TXN_WRITE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_TXN_WRITE 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DETERMINISTIC
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DETERMINISTIC 2048L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_DIRECTONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_DIRECTONLY 524288L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INNOCUOUS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INNOCUOUS 2097152L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_SCAN_UNIQUE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_SCAN_UNIQUE 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_EQ
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_EQ 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GT 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LE 8L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LT 16L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GE 32L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_MATCH
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_MATCH 64L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LIKE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LIKE 65L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GLOB
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_GLOB 66L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_REGEXP
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_REGEXP 67L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_NE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_NE 68L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNOT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNOT 69L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNOTNULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNULL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_ISNULL 71L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_IS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_IS 72L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LIMIT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_LIMIT 73L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_OFFSET
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_OFFSET 74L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_FUNCTION
+#define org_sqlite_jni_SQLite3Jni_SQLITE_INDEX_CONSTRAINT_FUNCTION 150L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_CONSTRAINT_SUPPORT
+#define org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_CONSTRAINT_SUPPORT 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_INNOCUOUS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_INNOCUOUS 2L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_DIRECTONLY
+#define org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_DIRECTONLY 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_USES_ALL_SCHEMAS
+#define org_sqlite_jni_SQLite3Jni_SQLITE_VTAB_USES_ALL_SCHEMAS 4L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_ROLLBACK
+#define org_sqlite_jni_SQLite3Jni_SQLITE_ROLLBACK 1L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_FAIL
+#define org_sqlite_jni_SQLite3Jni_SQLITE_FAIL 3L
+#undef org_sqlite_jni_SQLite3Jni_SQLITE_REPLACE
+#define org_sqlite_jni_SQLite3Jni_SQLITE_REPLACE 5L
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    init
+ * Signature: (Lorg/sqlite/jni/SQLite3Jni;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_init
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_blob
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1blob
+  (JNIEnv *, jclass, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_double
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;ID)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1double
+  (JNIEnv *, jclass, jobject, jint, jdouble);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_int
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;II)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1int
+  (JNIEnv *, jclass, jobject, jint, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_int64
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;IJ)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1int64
+  (JNIEnv *, jclass, jobject, jint, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_null
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1null
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_parameter_count
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1parameter_1count
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_parameter_index
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;[B)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1parameter_1index
+  (JNIEnv *, jclass, jobject, jbyteArray);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_text
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1text
+  (JNIEnv *, jclass, jobject, jint, jbyteArray, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_zeroblob
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;II)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1zeroblob
+  (JNIEnv *, jclass, jobject, jint, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_bind_zeroblob64
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;IJ)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1zeroblob64
+  (JNIEnv *, jclass, jobject, jint, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_busy_timeout
+ * Signature: (Lorg/sqlite/jni/sqlite3;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1timeout
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_changes
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1changes
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_changes64
+ * Signature: (Lorg/sqlite/jni/sqlite3;)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1changes64
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_clear_bindings
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1clear_1bindings
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_close
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1close
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_close_v2
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1close_1v2
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_blob
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1blob
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_bytes
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1bytes
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_bytes16
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1bytes16
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_count
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1count
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_double
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)D
+ */
+JNIEXPORT jdouble JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1double
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_int
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1int
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_int64
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1int64
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_name
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1name
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_database_name
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1database_1name
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_origin_name
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1origin_1name
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_table_name
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1table_1name
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_text
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_text_utf8
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1text_1utf8
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_type
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1type
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_column_value
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;I)Lorg/sqlite/jni/sqlite3_value;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1column_1value
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_context_db_handle
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;)Lorg/sqlite/jni/sqlite3;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1context_1db_1handle
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_compileoption_get
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1compileoption_1get
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_compileoption_used
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1compileoption_1used
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_create_collation
+ * Signature: (Lorg/sqlite/jni/sqlite3;Ljava/lang/String;ILorg/sqlite/jni/Collation;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1create_1collation
+  (JNIEnv *, jclass, jobject, jstring, jint, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_create_function
+ * Signature: (Lorg/sqlite/jni/sqlite3;Ljava/lang/String;IILorg/sqlite/jni/SQLFunction;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1create_1function
+  (JNIEnv *, jclass, jobject, jstring, jint, jint, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_data_count
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1data_1count
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_errcode
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1errcode
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_extended_errcode
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1extended_1errcode
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_extended_result_codes
+ * Signature: (Lorg/sqlite/jni/sqlite3;Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1extended_1result_1codes
+  (JNIEnv *, jclass, jobject, jboolean);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_errmsg
+ * Signature: (Lorg/sqlite/jni/sqlite3;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1errmsg
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_errstr
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1errstr
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_error_offset
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1error_1offset
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_finalize
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1finalize
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_initialize
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1initialize
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_last_insert_rowid
+ * Signature: (Lorg/sqlite/jni/sqlite3;)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1last_1insert_1rowid
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_libversion
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1libversion
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_libversion_number
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1libversion_1number
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_open
+ * Signature: (Ljava/lang/String;Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open
+  (JNIEnv *, jclass, jstring, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_open_v2
+ * Signature: (Ljava/lang/String;Lorg/sqlite/jni/sqlite3;ILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open_1v2
+  (JNIEnv *, jclass, jstring, jobject, jint, jstring);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_prepare
+ * Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare
+  (JNIEnv *, jclass, jobject, jbyteArray, jint, jobject, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_prepare_v2
+ * Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v2
+  (JNIEnv *, jclass, jobject, jbyteArray, jint, jobject, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_prepare_v3
+ * Signature: (Lorg/sqlite/jni/sqlite3;[BIILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v3
+  (JNIEnv *, jclass, jobject, jbyteArray, jint, jint, jobject, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_reset
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_double
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;D)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1double
+  (JNIEnv *, jclass, jobject, jdouble);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_error
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;[BI)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1error
+  (JNIEnv *, jclass, jobject, jbyteArray, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_error_toobig
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1error_1toobig
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_error_nomem
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1error_1nomem
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_error_code
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;I)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1error_1code
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_null
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1null
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_int
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;I)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1int
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_int64
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;J)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1int64
+  (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_java_object
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;Ljava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1java_1object
+  (JNIEnv *, jclass, jobject, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_value
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;Lorg/sqlite/jni/sqlite3_value;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1value
+  (JNIEnv *, jclass, jobject, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_zeroblob
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;I)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1zeroblob
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_zeroblob64
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;J)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1zeroblob64
+  (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_blob
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;[BI)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1blob
+  (JNIEnv *, jclass, jobject, jbyteArray, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_blob64
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;[BJ)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1blob64
+  (JNIEnv *, jclass, jobject, jbyteArray, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_text
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;[BI)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text
+  (JNIEnv *, jclass, jobject, jbyteArray, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_result_text64
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;[BJI)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64
+  (JNIEnv *, jclass, jobject, jbyteArray, jlong, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_set_last_insert_rowid
+ * Signature: (Lorg/sqlite/jni/sqlite3;J)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1set_1last_1insert_1rowid
+  (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_sleep
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1sleep
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_sourceid
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1sourceid
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_step
+ * Signature: (Lorg/sqlite/jni/sqlite3_stmt;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1step
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_threadsafe
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1threadsafe
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_total_changes
+ * Signature: (Lorg/sqlite/jni/sqlite3;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1total_1changes
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_total_changes64
+ * Signature: (Lorg/sqlite/jni/sqlite3;)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1total_1changes64
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_trace_v2
+ * Signature: (Lorg/sqlite/jni/sqlite3;ILorg/sqlite/jni/Tracer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1trace_1v2
+  (JNIEnv *, jclass, jobject, jint, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_blob
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1blob
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_bytes
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1bytes
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_bytes16
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1bytes16
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_double
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)D
+ */
+JNIEXPORT jdouble JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1double
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_dupe
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)Lorg/sqlite/jni/sqlite3_value;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1dupe
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_encoding
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1encoding
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_free
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1free
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_int
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1int
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_int64
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1int64
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_java_object
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1java_1object
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_text
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1text
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_text_utf8
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1text_1utf8
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_text16
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1text16
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_text16le
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1text16le
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_text16be
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1text16be
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_type
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1type
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_numeric_type
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1numeric_1type
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_nochange
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1nochange
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_frombind
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1frombind
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_value_subtype
+ * Signature: (Lorg/sqlite/jni/sqlite3_value;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1subtype
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_shutdown
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1shutdown
+  (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/ext/jni/src/org/sqlite/jni/Collation.java b/ext/jni/src/org/sqlite/jni/Collation.java
new file mode 100644 (file)
index 0000000..a05b8ef
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+** 2023-07-22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+*/
+public abstract class Collation {
+  /**
+     Must compare the given byte arrays using memcmp() semantics.
+  */
+  public abstract int xCompare(byte[] lhs, byte[] rhs);
+  /**
+     Called by SQLite when the collation is destroyed. If a Collation
+     requires custom cleanup, override this method.
+  */
+  public void xDestroy() {}
+}
diff --git a/ext/jni/src/org/sqlite/jni/NativePointerHolder.java b/ext/jni/src/org/sqlite/jni/NativePointerHolder.java
new file mode 100644 (file)
index 0000000..d6543ba
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   A helper for passing pointers between JNI C code and Java, in
+   particular for output pointers of high-level object types in the
+   sqlite3 C API, e.g. (sqlite3**) and (sqlite3_stmt**).  This is
+   intended to be subclassed and the ContextType is intended to be the
+   class which is doing the subclassing. The intent of the ContextType
+   is strictly to provide some level of type safety by avoiding that
+   NativePointerHolder is not inadvertently passed to an incompatible
+   function signature.
+
+   These objects are not intended to _own_ the pointer they refer to.
+   They are intended to simply communicate that pointer between C and
+   Java.
+*/
+public class NativePointerHolder<ContextType> {
+  private long pointer;
+  public NativePointerHolder(long pointer){
+    this.pointer = pointer;
+  }
+  public NativePointerHolder(){
+    this.pointer = 0;
+  }
+  public final long getNativePointer(){ return pointer; }
+  public final void setNativePointer(long p){ pointer = p; }
+}
diff --git a/ext/jni/src/org/sqlite/jni/OutputPointer.java b/ext/jni/src/org/sqlite/jni/OutputPointer.java
new file mode 100644 (file)
index 0000000..f4f2269
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   Helper classes for handling JNI output pointers for primitive
+   types. Higher-level classes which use output pointers have their
+   own corresponding Java class, e.g. sqlite3 and sqlite3_stmt.
+
+   We do not use a generic OutputPointer<T> because working with those
+   from the native JNI code is unduly quirky due to a lack of
+   autoboxing at that level.
+*/
+public final class OutputPointer {
+  public static final class Int32 {
+    private int value;
+    public final void setValue(int v){value = v;}
+    public final int getValue(){return value;}
+  }
+  public static final class Int64 {
+    private long value;
+    public final void setValue(long v){value = v;}
+    public final long getValue(){return value;}
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/ProgressHandler.java b/ext/jni/src/org/sqlite/jni/ProgressHandler.java
new file mode 100644 (file)
index 0000000..b3e8abc
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+** 2023-07-22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   Callback proxy for use with sqlite3_progress_handler().
+*/
+public interface ProgressHandler {
+  /**
+  */
+  int xCallback();
+}
diff --git a/ext/jni/src/org/sqlite/jni/SQLFunction.java b/ext/jni/src/org/sqlite/jni/SQLFunction.java
new file mode 100644 (file)
index 0000000..482bf45
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+** 2023-07-22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   SQLFunction is used in conjunction with the
+   sqlite3_create_function() JNI-bound API to give that native code
+   access to the callback functions needed in order to implement SQL
+   functions in Java. This class is not used by itself: see the
+   three inner classes.
+*/
+public abstract class SQLFunction {
+
+  //! Subclass for creating scalar functions.
+  public static abstract class Scalar extends SQLFunction {
+    public abstract void xFunc(sqlite3_context cx, sqlite3_value[] args);
+    /**
+       Optionally override to be notified when the function is
+       finalized by SQLite.
+    */
+    public void xDestroy() {}
+  }
+
+  //! Subclass for creating aggregate functions.
+  public static abstract class Aggregate extends SQLFunction {
+    public abstract void xStep(sqlite3_context cx, sqlite3_value[] args);
+    public abstract void xFinal(sqlite3_context cx);
+    public void xDestroy() {}
+  }
+
+  //! Subclass for creating window functions.
+  public static abstract class Window extends SQLFunction {
+    public abstract void xStep(sqlite3_context cx, sqlite3_value[] args);
+    public abstract void xInverse(sqlite3_context cx, sqlite3_value[] args);
+    public abstract void xFinal(sqlite3_context cx);
+    public abstract void xValue(sqlite3_context cx);
+    public void xDestroy() {}
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java
new file mode 100644 (file)
index 0000000..53b920f
--- /dev/null
@@ -0,0 +1,1202 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file declares JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+import java.nio.charset.StandardCharsets;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+   This annotation is for flagging parameters which may legally be
+   null, noting that they may behave different if passed null but are
+   prepared to expect null as a value.
+
+   This annotation is solely for the reader's information.
+*/
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+@interface Nullable{}
+
+/**
+   This annotation is for flagging parameters which may not legally be
+   null. Note that the C-style API does _not_ throw any
+   NullPointerExceptions on its own because it has a no-throw policy
+   in order to retain its C-style semantics.
+
+   This annotation is solely for the reader's information. No policy
+   is in place to programmatically ensure that NotNull is conformed to
+   in client code.
+*/
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+@interface NotNull{}
+
+/**
+  This class contains the entire sqlite3 JNI API binding.  For
+  client-side use, a static import is recommended:
+
+  ```
+  import static org.sqlite.jni.SQLite3Jni.*;
+  ```
+
+  The C-side part can be found in sqlite3-jni.c.
+
+
+  Only functions which materially differ from their C counterparts
+  are documented here. The C documetation is otherwise applicable
+  here:
+
+  https://sqlite.org/c3ref/intro.html
+
+  A small handful of Java-specific APIs have been added.
+*/
+public final class SQLite3Jni {
+  static {
+    System.loadLibrary("sqlite3-jni");
+  }
+  private SQLite3Jni(){}
+  private static native void init(@NotNull SQLite3Jni s);
+
+  //////////////////////////////////////////////////////////////////////
+  // Maintenance reminder: please keep the functions alphabetized.
+  // The SQLITE_... values. on the other hand, are grouped by category.
+
+  public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx,
+                                      @Nullable byte[] data){
+    return (null == data)
+      ? sqlite3_bind_null(stmt, ndx)
+      : sqlite3_bind_blob(stmt, ndx, data, data.length);
+  }
+
+  private static native int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt,
+                                              int ndx, @Nullable byte[] data,
+                                              int n);
+
+  public static native int sqlite3_bind_double(@NotNull sqlite3_stmt stmt,
+                                               int ndx, double v);
+
+  public static native int sqlite3_bind_int(@NotNull sqlite3_stmt stmt,
+                                            int ndx, int v);
+
+  public static native int sqlite3_bind_int64(@NotNull sqlite3_stmt stmt,
+                                              int ndx, long v);
+
+  public static native int sqlite3_bind_null(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native int sqlite3_bind_parameter_count(@NotNull sqlite3_stmt stmt);
+
+
+  private static native int sqlite3_bind_parameter_index(@NotNull sqlite3_stmt stmt,
+                                                         byte[] paramName);
+
+  public static int sqlite3_bind_parameter_index(@NotNull sqlite3_stmt stmt,
+                                                 @NotNull String paramName){
+    final byte[] utf8 = (paramName+"\0").getBytes(StandardCharsets.UTF_8);
+    return sqlite3_bind_parameter_index(stmt, utf8);
+  }
+
+  public static int sqlite3_bind_text(@NotNull sqlite3_stmt stmt, int ndx,
+                                      @Nullable String data){
+    if(null == data) return sqlite3_bind_null(stmt, ndx);
+    final byte[] utf8 = data.getBytes(StandardCharsets.UTF_8);
+    return sqlite3_bind_text(stmt, ndx, utf8, utf8.length);
+  }
+
+  public static int sqlite3_bind_text(@NotNull sqlite3_stmt stmt, int ndx,
+                                      @Nullable byte[] data){
+    return (null == data)
+      ? sqlite3_bind_null(stmt, ndx)
+      : sqlite3_bind_text(stmt, ndx, data, data.length);
+  }
+
+  /**
+     Works like the C-level sqlite3_bind_text() but (A) assumes
+     SQLITE_TRANSIENT for the final parameter and (B) behaves like
+     sqlite3_bind_null() if the data argument is null.
+  */
+  private static native int sqlite3_bind_text(@NotNull sqlite3_stmt stmt, int ndx,
+                                              @Nullable byte[] data, int maxBytes);
+
+  public static native int sqlite3_bind_zeroblob(@NotNull sqlite3_stmt stmt, int ndx, int n);
+
+  public static native int sqlite3_bind_zeroblob64(@NotNull sqlite3_stmt stmt, int ndx, long n);
+
+  //TODO? public static native int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
+
+  public static native int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms);
+
+  public static native int sqlite3_changes(@NotNull sqlite3 db);
+
+  public static native long sqlite3_changes64(@NotNull sqlite3 db);
+
+  public static native int sqlite3_clear_bindings(@NotNull sqlite3_stmt stmt);
+
+  public static native int sqlite3_close(@NotNull sqlite3 db);
+
+  public static native int sqlite3_close_v2(@NotNull sqlite3 db);
+
+  //TODO? public static native int sqlite3_collation_needed(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
+  //TODO? public static native int sqlite3_collation_needed16(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
+
+  public static native byte[] sqlite3_column_blob(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native int sqlite3_column_bytes(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native int sqlite3_column_bytes16(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native int sqlite3_column_count(@NotNull sqlite3_stmt stmt);
+
+  public static native double sqlite3_column_double(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native int sqlite3_column_int(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native long sqlite3_column_int64(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx);
+
+  public static native String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx);
+
+  /**
+     Column counterpart of sqlite3_value_java_object().
+  */
+  public static Object sqlite3_column_java_object(@NotNull sqlite3_stmt stmt,
+                                                  int ndx){
+    Object rv = null;
+    sqlite3_value v = sqlite3_column_value(stmt, ndx);
+    if(null!=v){
+      v = sqlite3_value_dupe(v) /* we need a "protected" value */;
+      if(null!=v){
+        rv = sqlite3_value_java_object(v);
+        sqlite3_value_free(v);
+      }
+    }
+    return rv;
+  }
+
+  /**
+     Column counterpart of sqlite3_value_java_casted().
+  */
+  @SuppressWarnings("unchecked")
+  public static <T> T sqlite3_column_java_casted(@NotNull sqlite3_stmt stmt,
+                                                 int ndx,
+                                                 @NotNull Class<T> type){
+    final Object o = sqlite3_column_java_object(stmt, ndx);
+    return (null!=o && type.isInstance(o)) ? (T)o : null;
+  }
+
+  public static native String sqlite3_column_origin_name(@NotNull sqlite3_stmt stmt, int ndx);
+
+  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().
+     This API includes no functions for working with Modified UTF-8.
+
+     [^1]: https://stackoverflow.com/questions/7921016
+  */
+  public static native String sqlite3_column_text(@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.
+  */
+  public static native byte[] sqlite3_column_text_utf8(@NotNull sqlite3_stmt stmt,
+                                                       int ndx);
+  //TODO public static native ?type? sqlite3_column_text16(@NotNull sqlite3_stmt stmt, int ndx);
+  //TODO: public static Object sqlite3_column_to_java(@NotNull sqlite3_value v){...}
+
+  public static native int sqlite3_column_type(@NotNull sqlite3_stmt stmt,
+                                               int ndx);
+
+  public static native sqlite3_value sqlite3_column_value(@NotNull sqlite3_stmt stmt,
+                                                          int ndx);
+
+  // TODO public static native int sqlite3_collation_needed(
+  //sqlite3 db, void(*)(void*,sqlite3*,int eTextRep,const char*))
+
+  //TODO public static native int sqlite3_collation_needed16(
+  //  sqlite3 db, void(*)(void*,sqlite3*,int eTextRep,const void*)
+
+  public static native sqlite3 sqlite3_context_db_handle(@NotNull sqlite3_context cx);
+
+  //TODO? void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+
+  public static native String sqlite3_compileoption_get(int n);
+
+  public static native boolean sqlite3_compileoption_used(@NotNull String optName);
+
+  public static native int sqlite3_create_collation(@NotNull sqlite3 db,
+                                                    @NotNull String name,
+                                                    int eTextRep,
+                                                    @NotNull Collation col);
+
+  //! Convenience overload which assumes SQLITE_UTF8 encoding.
+  public static int sqlite3_create_collation(@NotNull sqlite3 db,
+                                             @NotNull String name,
+                                             @NotNull Collation col){
+    return sqlite3_create_collation(db, name, SQLITE_UTF8, col);
+  }
+
+  public static native int sqlite3_create_function(@NotNull sqlite3 db,
+                                                   @NotNull String functionName,
+                                                   int nArg, int eTextRep,
+                                                   @NotNull SQLFunction func);
+
+  public static native int sqlite3_data_count(@NotNull sqlite3_stmt stmt);
+
+  public static native int sqlite3_errcode(@NotNull sqlite3 db);
+
+  public static native int sqlite3_extended_errcode(@NotNull sqlite3 db);
+
+  public static native boolean sqlite3_extended_result_codes(@NotNull sqlite3 db,
+                                                             boolean onoff);
+
+  public static native String sqlite3_errmsg(@NotNull sqlite3 db);
+
+  public static native String sqlite3_errstr(int resultCode);
+
+  public static native int sqlite3_error_offset(@NotNull sqlite3 db);
+
+  public static native int sqlite3_finalize(@NotNull sqlite3_stmt stmt);
+
+  public static native int sqlite3_initialize();
+
+  public static native long sqlite3_last_insert_rowid(@NotNull sqlite3 db);
+
+  //TODO? void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+
+  public static native String sqlite3_libversion();
+
+  public static native int sqlite3_libversion_number();
+
+  public static native int sqlite3_open(@Nullable String filename,
+                                        @NotNull sqlite3 ppDb);
+
+  public static native int sqlite3_open_v2(@Nullable String filename,
+                                           @NotNull sqlite3 ppDb,
+                                           int flags, @Nullable String zVfs);
+
+  /**
+     The sqlite3_prepare() family of functions require slightly
+     different signatures than their native counterparts, but
+     overloading allows us to install several convenience forms.
+
+     All of them which take their SQL in the form of a byte[] require
+     that it be in UTF-8 encoding unless explicitly noted otherwise.
+
+     The forms which take a "tail" output pointer return (via that
+     output object) the index into their SQL byte array at which the
+     end of the first SQL statement processed by the call was
+     found. That's fundamentally how the C APIs work but making use of
+     that value requires more copying of the input SQL into
+     consecutively smaller arrays in order to consume all of
+     it. (There is an example of doing that in this project's Tester1
+     class.) For that vast majority of uses, that capability is not
+     necessary, however, and overloads are provided which gloss over
+     that.
+  */
+  private static native int sqlite3_prepare(@NotNull sqlite3 db,
+                                            @NotNull byte[] sqlUtf8, int maxBytes,
+                                            @NotNull sqlite3_stmt outStmt,
+                                            @Nullable OutputPointer.Int32 pTailOffset);
+
+  public static int sqlite3_prepare(@NotNull sqlite3 db,
+                                    @NotNull byte[] sqlUtf8,
+                                    @NotNull sqlite3_stmt outStmt,
+                                    @Nullable OutputPointer.Int32 pTailOffset){
+    return sqlite3_prepare(db, sqlUtf8, sqlUtf8.length, outStmt, pTailOffset);
+  }
+
+  public static int sqlite3_prepare(@NotNull sqlite3 db,
+                                    @NotNull byte[] sqlUtf8,
+                                    @NotNull sqlite3_stmt outStmt){
+    return sqlite3_prepare(db, sqlUtf8, sqlUtf8.length, outStmt, null);
+  }
+
+  public static int sqlite3_prepare(@NotNull sqlite3 db, @NotNull String sql,
+                                    @NotNull sqlite3_stmt outStmt){
+    final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
+    return sqlite3_prepare(db, utf8, utf8.length, outStmt, null);
+  }
+
+  private static native int sqlite3_prepare_v2(@NotNull sqlite3 db,
+                                               @NotNull byte[] sqlUtf8,
+                                               int maxBytes,
+                                               @NotNull sqlite3_stmt outStmt,
+                                               @Nullable OutputPointer.Int32 pTailOffset);
+
+  public static int sqlite3_prepare_v2(@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
+                                       @NotNull sqlite3_stmt outStmt,
+                                       @Nullable OutputPointer.Int32 pTailOffset){
+    return sqlite3_prepare_v2(db, sqlUtf8, sqlUtf8.length, outStmt, pTailOffset);
+  }
+
+  public static int sqlite3_prepare_v2(@NotNull sqlite3 db,
+                                       @NotNull byte[] sqlUtf8,
+                                       @NotNull sqlite3_stmt outStmt){
+    return sqlite3_prepare_v2(db, sqlUtf8, sqlUtf8.length, outStmt, null);
+  }
+
+  public static int sqlite3_prepare_v2(@NotNull sqlite3 db,
+                                       @NotNull String sql,
+                                       @NotNull sqlite3_stmt outStmt){
+    final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
+    return sqlite3_prepare_v2(db, utf8, utf8.length, outStmt, null);
+  }
+
+  private static native int sqlite3_prepare_v3(@NotNull sqlite3 db,
+                                               @NotNull byte[] sqlUtf8,
+                                               int maxBytes, int prepFlags,
+                                               @NotNull sqlite3_stmt outStmt,
+                                               @Nullable OutputPointer.Int32 pTailOffset);
+
+  public static int sqlite3_prepare_v3(@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
+                                       int prepFlags,
+                                       @NotNull sqlite3_stmt outStmt,
+                                       @Nullable OutputPointer.Int32 pTailOffset){
+    return sqlite3_prepare_v3(db, sqlUtf8, sqlUtf8.length, prepFlags, outStmt, pTailOffset);
+  }
+
+  public static int sqlite3_prepare_v3(@NotNull sqlite3 db,
+                                       @NotNull byte[] sqlUtf8,
+                                       int prepFlags,
+                                       @NotNull sqlite3_stmt outStmt){
+    return sqlite3_prepare_v3(db, sqlUtf8, sqlUtf8.length, prepFlags, outStmt, null);
+  }
+
+  public static int sqlite3_prepare_v3(@NotNull sqlite3 db, @NotNull String sql,
+                                       int prepFlags, @NotNull sqlite3_stmt outStmt){
+    final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
+    return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null);
+  }
+
+
+  //TODO public static native void sqlite3_progress_handler(sqlite3 db, int n, ProgressHandler h);
+
+  public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt);
+
+  public static native void sqlite3_result_double(@NotNull sqlite3_context cx, double v);
+
+  /**
+     The main sqlite3_result_error() impl of which all others are
+     proxies. eTextRep must be one of SQLITE_UTF8 or SQLITE_UTF16 and
+     msg must be encoded correspondingly. Any other eTextRep value
+     results in the C-level sqlite3_result_error() being called with
+     a complaint about the invalid argument.
+  */
+  private static native void sqlite3_result_error(@NotNull sqlite3_context cx,
+                                                  @Nullable byte[] msg,
+                                                  int eTextRep);
+
+  public static void sqlite3_result_error(@NotNull sqlite3_context cx,
+                                          @NotNull byte[] utf8){
+    sqlite3_result_error(cx, utf8, SQLITE_UTF8);
+  }
+
+  public static void sqlite3_result_error(@NotNull sqlite3_context cx,
+                                          @NotNull String msg){
+    final byte[] utf8 = (msg+"\0").getBytes(StandardCharsets.UTF_8);
+    sqlite3_result_error(cx, utf8, SQLITE_UTF8);
+  }
+
+  public static void sqlite3_result_error16(@NotNull sqlite3_context cx,
+                                            @Nullable byte[] utf16){
+    sqlite3_result_error(cx, utf16, SQLITE_UTF16);
+  }
+
+  public static void sqlite3_result_error16(@NotNull sqlite3_context cx,
+                                            @NotNull String msg){
+    final byte[] utf8 = (msg+"\0").getBytes(StandardCharsets.UTF_16);
+    sqlite3_result_error(cx, utf8, SQLITE_UTF16);
+  }
+
+  public static void sqlite3_result_error(@NotNull sqlite3_context cx,
+                                          @NotNull Exception e){
+    sqlite3_result_error(cx, e.getMessage());
+  }
+
+  public static void sqlite3_result_error16(@NotNull sqlite3_context cx,
+                                            @NotNull Exception e){
+    sqlite3_result_error16(cx, e.getMessage());
+  }
+
+  public static native void sqlite3_result_error_toobig(@NotNull sqlite3_context cx);
+
+  public static native void sqlite3_result_error_nomem(@NotNull sqlite3_context cx);
+
+  public static native void sqlite3_result_error_code(@NotNull sqlite3_context cx, int c);
+
+  public static native void sqlite3_result_null(@NotNull sqlite3_context cx);
+
+  public static native void sqlite3_result_int(@NotNull sqlite3_context cx, int v);
+
+  public static native void sqlite3_result_int64(@NotNull sqlite3_context cx, long v);
+
+  /**
+     Binds the SQL result to the given object, or
+     sqlite3_result_null() if o is null. Use
+     sqlite3_value_java_object() or sqlite3_column_java_object() to
+     fetch it.
+
+     This is implemented in terms of sqlite3_result_pointer(), but
+     that function is not exposed to JNI because its 3rd argument must
+     be a constant string (the library does not copy it), which we
+     cannot implement cross-language here unless, in the JNI layer, we
+     allocate such strings and store them somewhere for long-term use
+     (leaking them more likely than not). Even then, passing around a
+     pointer via Java like that has little practical use.
+  */
+  public static native void sqlite3_result_java_object(@NotNull sqlite3_context cx,
+                                                       @NotNull Object o);
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx,
+                                        @NotNull Integer v){
+    sqlite3_result_int(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx, int v){
+    sqlite3_result_int(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx,
+                                        @NotNull Boolean v){
+    sqlite3_result_int(cx, v ? 1 : 0);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx, boolean v){
+    sqlite3_result_int(cx, v ? 1 : 0);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx,
+                                        @NotNull Long v){
+    sqlite3_result_int64(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx, long v){
+    sqlite3_result_int64(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx,
+                                        @NotNull Double v){
+    sqlite3_result_double(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx, double v){
+    sqlite3_result_double(cx, v);
+  }
+
+  public static void sqlite3_result_set(@NotNull sqlite3_context cx,
+                                        @Nullable String v){
+    sqlite3_result_text(cx, v);
+  }
+
+  public static native void sqlite3_result_value(@NotNull sqlite3_context cx,
+                                                 @NotNull sqlite3_value v);
+
+  public static native void sqlite3_result_zeroblob(@NotNull sqlite3_context cx,
+                                                    int n);
+
+  public static native int sqlite3_result_zeroblob64(@NotNull sqlite3_context cx,
+                                                     long n);
+
+  private static native void sqlite3_result_blob(@NotNull sqlite3_context cx,
+                                                 @Nullable byte[] blob,
+                                                 int maxLen);
+
+  public static void sqlite3_result_blob(@NotNull sqlite3_context cx, @Nullable byte[] blob){
+    sqlite3_result_blob(cx, blob, (int)(null==blob ? 0 : blob.length));
+  }
+
+  /**
+     Binds the given text using C's sqlite3_result_blob64() unless:
+
+     - blob is null ==> sqlite3_result_null()
+
+     - blob is too large ==> sqlite3_result_error_toobig()
+
+     If maxLen is larger than blob.length, it is truncated to that
+     value. If it is negative, results are undefined.
+  */
+  private static native void sqlite3_result_blob64(@NotNull sqlite3_context cx,
+                                                   @Nullable byte[] blob,
+                                                   long maxLen);
+
+  public static void sqlite3_result_blob64(@NotNull sqlite3_context cx,
+                                           @Nullable byte[] blob){
+    sqlite3_result_blob64(cx, blob, (long)(null==blob ? 0 : blob.length));
+  }
+
+  private static native void sqlite3_result_text(@NotNull sqlite3_context cx,
+                                                 @Nullable byte[] text, int maxLen);
+
+  public static void sqlite3_result_text(@NotNull sqlite3_context cx,
+                                         @Nullable byte[] text){
+    sqlite3_result_text(cx, text, null==text ? 0 : text.length);
+  }
+
+  public static void sqlite3_result_text(@NotNull sqlite3_context cx,
+                                         @Nullable String text){
+    if(null == text) sqlite3_result_null(cx);
+    else{
+      final byte[] utf8 = text.getBytes(StandardCharsets.UTF_8);
+      sqlite3_result_text(cx, utf8, utf8.length);
+    }
+  }
+
+  /**
+     Binds the given text using C's sqlite3_result_text64() unless:
+
+     - text is null ==> sqlite3_result_null()
+
+     - text is too large ==> sqlite3_result_error_toobig()
+
+     - The `encoding` argument has an invalid value ==>
+       sqlite3_result_error_code() with SQLITE_FORMAT
+
+     If maxLength (in bytes, not characters) is larger than
+     text.length, it is silently truncated to text.length. If it is
+     negative, results are undefined.
+  */
+  private static native void sqlite3_result_text64(@NotNull sqlite3_context cx,
+                                                   @Nullable byte[] text,
+                                                   long maxLength, int encoding);
+
+  /**
+     Sets the current UDF result to the given bytes, which are assumed
+     be encoded in UTF-16 using the platform's byte order.
+  */
+  public static void sqlite3_result_text16(@NotNull sqlite3_context cx,
+                                           @Nullable byte[] text){
+    sqlite3_result_text64(cx, text, text.length, SQLITE_UTF16);
+  }
+
+  public static void sqlite3_result_text16(@NotNull sqlite3_context cx,
+                                           @Nullable String text){
+    if(null == text) sqlite3_result_null(cx);
+    else{
+      final byte[] b = text.getBytes(StandardCharsets.UTF_16);
+      sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16);
+    }
+  }
+
+  /**
+     Sets the current UDF result to the given bytes, which are assumed
+     be encoded in UTF-16LE.
+  */
+  public static void sqlite3_result_text16le(@NotNull sqlite3_context cx,
+                                             @Nullable String text){
+    if(null == text) sqlite3_result_null(cx);
+    else{
+      final byte[] b = text.getBytes(StandardCharsets.UTF_16LE);
+      sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16LE);
+    }
+  }
+
+  /**
+     Sets the current UDF result to the given bytes, which are assumed
+     be encoded in UTF-16BE.
+  */
+  public static void sqlite3_result_text16be(@NotNull sqlite3_context cx,
+                                             @Nullable byte[] text){
+    sqlite3_result_text64(cx, text, text.length, SQLITE_UTF16BE);
+  }
+
+  public static void sqlite3_result_text16be(@NotNull sqlite3_context cx,
+                                             @NotNull String text){
+    final byte[] b = text.getBytes(StandardCharsets.UTF_16BE);
+    sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16BE);
+  }
+
+  /**
+  public static void sqlite3_result_text64(@NotNull sqlite3_context cx,
+                                           @Nullable byte[] text){
+    sqlite3_result_text64(cx, text, null==text ? 0 : text.length, SQLITE_UTF8);
+  }**/
+
+  public static native void sqlite3_set_last_insert_rowid(@NotNull sqlite3 db, long rowid);
+
+  public static native int sqlite3_sleep(int ms);
+
+  public static native String sqlite3_sourceid();
+
+  public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
+
+  public static native int sqlite3_threadsafe();
+
+  public static native int sqlite3_total_changes(@NotNull sqlite3 db);
+
+  public static native long sqlite3_total_changes64(@NotNull sqlite3 db);
+
+  /**
+     Works like C's sqlite3_trace_v2() except that the 3rd argument to that
+     function is elided here because the roles of that functions' 3rd and 4th
+     arguments are encapsulated in the final argument to this function.
+
+     Unlike the C API, which is documented as always returning 0, this
+     implementation returns SQLITE_NOMEM if allocation of per-db
+     mapping state fails and SQLITE_ERROR if the given callback object
+     cannot be processed propertly (i.e. an internal error).
+  */
+  public static native int sqlite3_trace_v2(@NotNull sqlite3 db, int traceMask,
+                                            @Nullable Tracer tracer);
+
+  public static native byte[] sqlite3_value_blob(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_bytes(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_bytes16(@NotNull sqlite3_value v);
+
+  public static native double sqlite3_value_double(@NotNull sqlite3_value v);
+
+  public static native sqlite3_value sqlite3_value_dupe(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_encoding(@NotNull sqlite3_value v);
+
+  public static native void sqlite3_value_free(@Nullable sqlite3_value v);
+
+  public static native int sqlite3_value_int(@NotNull sqlite3_value v);
+
+  public static native long sqlite3_value_int64(@NotNull sqlite3_value v);
+
+  /**
+     If the given value was set using sqlite3_result_java_value() then
+     this function returns that object, else it returns null.
+
+     It is up to the caller to inspect the object to determine its
+     type, and cast it if necessary.
+  */
+  public static native Object sqlite3_value_java_object(@NotNull sqlite3_value v);
+
+  /**
+     A variant of sqlite3_value_java_object() which returns the
+     fetched object cast to T if the object is an instance of the
+     given Class. It returns null in all other cases.
+  */
+  @SuppressWarnings("unchecked")
+  public static <T> T sqlite3_value_java_casted(@NotNull sqlite3_value v,
+                                                @NotNull Class<T> type){
+    final Object o = sqlite3_value_java_object(v);
+    return (null!=o && type.isInstance(o)) ? (T)o : null;
+  }
+
+  /**
+     See sqlite3_column_text() for notes about encoding conversions.
+     See sqlite3_value_text_utf8() for how to extract text in standard
+     UTF-8.
+  */
+  public static native String sqlite3_value_text(@NotNull sqlite3_value v);
+
+  /**
+     The sqlite3_value counterpart of sqlite3_column_text_utf8().
+  */
+  public static native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v);
+
+  public static native byte[] sqlite3_value_text16(@NotNull sqlite3_value v);
+
+  public static native byte[] sqlite3_value_text16le(@NotNull sqlite3_value v);
+
+  public static native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v);
+
+  //TODO: to_java() should return a closest-match type for the given
+  //value. The quirk is that it would need to return object-type values,
+  //e.g. Integer instead of int, and creating those is a bit of a nuisance
+  //from JNI.
+  //public static native Object sqlite3_value_to_java(@NotNull sqlite3_value v);
+  // Or we can just implement it in Java:
+  //public static Object sqlite3_value_to_java(@NotNull sqlite3_value v){...}
+
+  public static native int sqlite3_value_type(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_numeric_type(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_nochange(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_frombind(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_value_subtype(@NotNull sqlite3_value v);
+
+  public static native int sqlite3_shutdown();
+
+  //////////////////////////////////////////////////////////////////////
+  // SQLITE_... constants follow...
+
+  // version info
+  public static final int SQLITE_VERSION_NUMBER = sqlite3_libversion_number();
+  public static final String SQLITE_VERSION = sqlite3_libversion();
+  public static final String SQLITE_SOURCE_ID = sqlite3_sourceid();
+
+  // access
+  public static final int SQLITE_ACCESS_EXISTS = 0;
+  public static final int SQLITE_ACCESS_READWRITE = 1;
+  public static final int SQLITE_ACCESS_READ = 2;
+
+  // authorizer
+  public static final int SQLITE_DENY = 1;
+  public static final int SQLITE_IGNORE = 2;
+  public static final int SQLITE_CREATE_INDEX = 1;
+  public static final int SQLITE_CREATE_TABLE = 2;
+  public static final int SQLITE_CREATE_TEMP_INDEX = 3;
+  public static final int SQLITE_CREATE_TEMP_TABLE = 4;
+  public static final int SQLITE_CREATE_TEMP_TRIGGER = 5;
+  public static final int SQLITE_CREATE_TEMP_VIEW = 6;
+  public static final int SQLITE_CREATE_TRIGGER = 7;
+  public static final int SQLITE_CREATE_VIEW = 8;
+  public static final int SQLITE_DELETE = 9;
+  public static final int SQLITE_DROP_INDEX = 10;
+  public static final int SQLITE_DROP_TABLE = 11;
+  public static final int SQLITE_DROP_TEMP_INDEX = 12;
+  public static final int SQLITE_DROP_TEMP_TABLE = 13;
+  public static final int SQLITE_DROP_TEMP_TRIGGER = 14;
+  public static final int SQLITE_DROP_TEMP_VIEW = 15;
+  public static final int SQLITE_DROP_TRIGGER = 16;
+  public static final int SQLITE_DROP_VIEW = 17;
+  public static final int SQLITE_INSERT = 18;
+  public static final int SQLITE_PRAGMA = 19;
+  public static final int SQLITE_READ = 20;
+  public static final int SQLITE_SELECT = 21;
+  public static final int SQLITE_TRANSACTION = 22;
+  public static final int SQLITE_UPDATE = 23;
+  public static final int SQLITE_ATTACH = 24;
+  public static final int SQLITE_DETACH = 25;
+  public static final int SQLITE_ALTER_TABLE = 26;
+  public static final int SQLITE_REINDEX = 27;
+  public static final int SQLITE_ANALYZE = 28;
+  public static final int SQLITE_CREATE_VTABLE = 29;
+  public static final int SQLITE_DROP_VTABLE = 30;
+  public static final int SQLITE_FUNCTION = 31;
+  public static final int SQLITE_SAVEPOINT = 32;
+  public static final int SQLITE_RECURSIVE = 33;
+
+  // blob finalizers:
+  public static final int SQLITE_STATIC = 0;
+  public static final int SQLITE_TRANSIENT = -1;
+
+  // changeset
+  public static final int SQLITE_CHANGESETSTART_INVERT = 2;
+  public static final int SQLITE_CHANGESETAPPLY_NOSAVEPOINT = 1;
+  public static final int SQLITE_CHANGESETAPPLY_INVERT = 2;
+  public static final int SQLITE_CHANGESETAPPLY_IGNORENOOP = 4;
+  public static final int SQLITE_CHANGESET_DATA = 1;
+  public static final int SQLITE_CHANGESET_NOTFOUND = 2;
+  public static final int SQLITE_CHANGESET_CONFLICT = 3;
+  public static final int SQLITE_CHANGESET_CONSTRAINT = 4;
+  public static final int SQLITE_CHANGESET_FOREIGN_KEY = 5;
+  public static final int SQLITE_CHANGESET_OMIT = 0;
+  public static final int SQLITE_CHANGESET_REPLACE = 1;
+  public static final int SQLITE_CHANGESET_ABORT = 2;
+
+  // config
+  public static final int SQLITE_CONFIG_SINGLETHREAD = 1;
+  public static final int SQLITE_CONFIG_MULTITHREAD = 2;
+  public static final int SQLITE_CONFIG_SERIALIZED = 3;
+  public static final int SQLITE_CONFIG_MALLOC = 4;
+  public static final int SQLITE_CONFIG_GETMALLOC = 5;
+  public static final int SQLITE_CONFIG_SCRATCH = 6;
+  public static final int SQLITE_CONFIG_PAGECACHE = 7;
+  public static final int SQLITE_CONFIG_HEAP = 8;
+  public static final int SQLITE_CONFIG_MEMSTATUS = 9;
+  public static final int SQLITE_CONFIG_MUTEX = 10;
+  public static final int SQLITE_CONFIG_GETMUTEX = 11;
+  public static final int SQLITE_CONFIG_LOOKASIDE = 13;
+  public static final int SQLITE_CONFIG_PCACHE = 14;
+  public static final int SQLITE_CONFIG_GETPCACHE = 15;
+  public static final int SQLITE_CONFIG_LOG = 16;
+  public static final int SQLITE_CONFIG_URI = 17;
+  public static final int SQLITE_CONFIG_PCACHE2 = 18;
+  public static final int SQLITE_CONFIG_GETPCACHE2 = 19;
+  public static final int SQLITE_CONFIG_COVERING_INDEX_SCAN = 20;
+  public static final int SQLITE_CONFIG_SQLLOG = 21;
+  public static final int SQLITE_CONFIG_MMAP_SIZE = 22;
+  public static final int SQLITE_CONFIG_WIN32_HEAPSIZE = 23;
+  public static final int SQLITE_CONFIG_PCACHE_HDRSZ = 24;
+  public static final int SQLITE_CONFIG_PMASZ = 25;
+  public static final int SQLITE_CONFIG_STMTJRNL_SPILL = 26;
+  public static final int SQLITE_CONFIG_SMALL_MALLOC = 27;
+  public static final int SQLITE_CONFIG_SORTERREF_SIZE = 28;
+  public static final int SQLITE_CONFIG_MEMDB_MAXSIZE = 29;
+
+  // data types
+  public static final int SQLITE_INTEGER = 1;
+  public static final int SQLITE_FLOAT = 2;
+  public static final int SQLITE_TEXT = 3;
+  public static final int SQLITE_BLOB = 4;
+  public static final int SQLITE_NULL = 5;
+
+  // db config
+  public static final int SQLITE_DBCONFIG_MAINDBNAME = 1000;
+  public static final int SQLITE_DBCONFIG_LOOKASIDE = 1001;
+  public static final int SQLITE_DBCONFIG_ENABLE_FKEY = 1002;
+  public static final int SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003;
+  public static final int SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004;
+  public static final int SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005;
+  public static final int SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006;
+  public static final int SQLITE_DBCONFIG_ENABLE_QPSG = 1007;
+  public static final int SQLITE_DBCONFIG_TRIGGER_EQP = 1008;
+  public static final int SQLITE_DBCONFIG_RESET_DATABASE = 1009;
+  public static final int SQLITE_DBCONFIG_DEFENSIVE = 1010;
+  public static final int SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011;
+  public static final int SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1012;
+  public static final int SQLITE_DBCONFIG_DQS_DML = 1013;
+  public static final int SQLITE_DBCONFIG_DQS_DDL = 1014;
+  public static final int SQLITE_DBCONFIG_ENABLE_VIEW = 1015;
+  public static final int SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1016;
+  public static final int SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017;
+  public static final int SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018;
+  public static final int SQLITE_DBCONFIG_REVERSE_SCANORDER = 1019;
+  public static final int SQLITE_DBCONFIG_MAX = 1019;
+
+  // db status
+  public static final int SQLITE_DBSTATUS_LOOKASIDE_USED = 0;
+  public static final int SQLITE_DBSTATUS_CACHE_USED = 1;
+  public static final int SQLITE_DBSTATUS_SCHEMA_USED = 2;
+  public static final int SQLITE_DBSTATUS_STMT_USED = 3;
+  public static final int SQLITE_DBSTATUS_LOOKASIDE_HIT = 4;
+  public static final int SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE = 5;
+  public static final int SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL = 6;
+  public static final int SQLITE_DBSTATUS_CACHE_HIT = 7;
+  public static final int SQLITE_DBSTATUS_CACHE_MISS = 8;
+  public static final int SQLITE_DBSTATUS_CACHE_WRITE = 9;
+  public static final int SQLITE_DBSTATUS_DEFERRED_FKS = 10;
+  public static final int SQLITE_DBSTATUS_CACHE_USED_SHARED = 11;
+  public static final int SQLITE_DBSTATUS_CACHE_SPILL = 12;
+  public static final int SQLITE_DBSTATUS_MAX = 12;
+
+  // encodings
+  public static final int SQLITE_UTF8 = 1;
+  public static final int SQLITE_UTF16LE = 2;
+  public static final int SQLITE_UTF16BE = 3;
+  public static final int SQLITE_UTF16 = 4;
+  public static final int SQLITE_UTF16_ALIGNED = 8;
+
+  // fcntl
+  public static final int SQLITE_FCNTL_LOCKSTATE = 1;
+  public static final int SQLITE_FCNTL_GET_LOCKPROXYFILE = 2;
+  public static final int SQLITE_FCNTL_SET_LOCKPROXYFILE = 3;
+  public static final int SQLITE_FCNTL_LAST_ERRNO = 4;
+  public static final int SQLITE_FCNTL_SIZE_HINT = 5;
+  public static final int SQLITE_FCNTL_CHUNK_SIZE = 6;
+  public static final int SQLITE_FCNTL_FILE_POINTER = 7;
+  public static final int SQLITE_FCNTL_SYNC_OMITTED = 8;
+  public static final int SQLITE_FCNTL_WIN32_AV_RETRY = 9;
+  public static final int SQLITE_FCNTL_PERSIST_WAL = 10;
+  public static final int SQLITE_FCNTL_OVERWRITE = 11;
+  public static final int SQLITE_FCNTL_VFSNAME = 12;
+  public static final int SQLITE_FCNTL_POWERSAFE_OVERWRITE = 13;
+  public static final int SQLITE_FCNTL_PRAGMA = 14;
+  public static final int SQLITE_FCNTL_BUSYHANDLER = 15;
+  public static final int SQLITE_FCNTL_TEMPFILENAME = 16;
+  public static final int SQLITE_FCNTL_MMAP_SIZE = 18;
+  public static final int SQLITE_FCNTL_TRACE = 19;
+  public static final int SQLITE_FCNTL_HAS_MOVED = 20;
+  public static final int SQLITE_FCNTL_SYNC = 21;
+  public static final int SQLITE_FCNTL_COMMIT_PHASETWO = 22;
+  public static final int SQLITE_FCNTL_WIN32_SET_HANDLE = 23;
+  public static final int SQLITE_FCNTL_WAL_BLOCK = 24;
+  public static final int SQLITE_FCNTL_ZIPVFS = 25;
+  public static final int SQLITE_FCNTL_RBU = 26;
+  public static final int SQLITE_FCNTL_VFS_POINTER = 27;
+  public static final int SQLITE_FCNTL_JOURNAL_POINTER = 28;
+  public static final int SQLITE_FCNTL_WIN32_GET_HANDLE = 29;
+  public static final int SQLITE_FCNTL_PDB = 30;
+  public static final int SQLITE_FCNTL_BEGIN_ATOMIC_WRITE = 31;
+  public static final int SQLITE_FCNTL_COMMIT_ATOMIC_WRITE = 32;
+  public static final int SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE = 33;
+  public static final int SQLITE_FCNTL_LOCK_TIMEOUT = 34;
+  public static final int SQLITE_FCNTL_DATA_VERSION = 35;
+  public static final int SQLITE_FCNTL_SIZE_LIMIT = 36;
+  public static final int SQLITE_FCNTL_CKPT_DONE = 37;
+  public static final int SQLITE_FCNTL_RESERVE_BYTES = 38;
+  public static final int SQLITE_FCNTL_CKPT_START = 39;
+  public static final int SQLITE_FCNTL_EXTERNAL_READER = 40;
+  public static final int SQLITE_FCNTL_CKSM_FILE = 41;
+  public static final int SQLITE_FCNTL_RESET_CACHE = 42;
+
+  // flock
+  public static final int SQLITE_LOCK_NONE = 0;
+  public static final int SQLITE_LOCK_SHARED = 1;
+  public static final int SQLITE_LOCK_RESERVED = 2;
+  public static final int SQLITE_LOCK_PENDING = 3;
+  public static final int SQLITE_LOCK_EXCLUSIVE = 4;
+
+  // iocap
+  public static final int SQLITE_IOCAP_ATOMIC = 1;
+  public static final int SQLITE_IOCAP_ATOMIC512 = 2;
+  public static final int SQLITE_IOCAP_ATOMIC1K = 4;
+  public static final int SQLITE_IOCAP_ATOMIC2K = 8;
+  public static final int SQLITE_IOCAP_ATOMIC4K = 16;
+  public static final int SQLITE_IOCAP_ATOMIC8K = 32;
+  public static final int SQLITE_IOCAP_ATOMIC16K = 64;
+  public static final int SQLITE_IOCAP_ATOMIC32K = 128;
+  public static final int SQLITE_IOCAP_ATOMIC64K = 256;
+  public static final int SQLITE_IOCAP_SAFE_APPEND = 512;
+  public static final int SQLITE_IOCAP_SEQUENTIAL = 1024;
+  public static final int SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN = 2048;
+  public static final int SQLITE_IOCAP_POWERSAFE_OVERWRITE = 4096;
+  public static final int SQLITE_IOCAP_IMMUTABLE = 8192;
+  public static final int SQLITE_IOCAP_BATCH_ATOMIC = 16384;
+
+  // limits. These get injected at init-time so that they stay in sync
+  // with the compile-time options. This unfortunately means they are
+  // not final, but keeping them in sync with their C values seems
+  // more important than protecting users from assigning to these
+  // (with unpredictable results).
+  public static int SQLITE_MAX_ALLOCATION_SIZE = -1;
+  public static int SQLITE_LIMIT_LENGTH = -1;
+  public static int SQLITE_MAX_LENGTH = -1;
+  public static int SQLITE_LIMIT_SQL_LENGTH = -1;
+  public static int SQLITE_MAX_SQL_LENGTH = -1;
+  public static int SQLITE_LIMIT_COLUMN = -1;
+  public static int SQLITE_MAX_COLUMN = -1;
+  public static int SQLITE_LIMIT_EXPR_DEPTH = -1;
+  public static int SQLITE_MAX_EXPR_DEPTH = -1;
+  public static int SQLITE_LIMIT_COMPOUND_SELECT = -1;
+  public static int SQLITE_MAX_COMPOUND_SELECT = -1;
+  public static int SQLITE_LIMIT_VDBE_OP = -1;
+  public static int SQLITE_MAX_VDBE_OP = -1;
+  public static int SQLITE_LIMIT_FUNCTION_ARG = -1;
+  public static int SQLITE_MAX_FUNCTION_ARG = -1;
+  public static int SQLITE_LIMIT_ATTACHED = -1;
+  public static int SQLITE_MAX_ATTACHED = -1;
+  public static int SQLITE_LIMIT_LIKE_PATTERN_LENGTH = -1;
+  public static int SQLITE_MAX_LIKE_PATTERN_LENGTH = -1;
+  public static int SQLITE_LIMIT_VARIABLE_NUMBER = -1;
+  public static int SQLITE_MAX_VARIABLE_NUMBER = -1;
+  public static int SQLITE_LIMIT_TRIGGER_DEPTH = -1;
+  public static int SQLITE_MAX_TRIGGER_DEPTH = -1;
+  public static int SQLITE_LIMIT_WORKER_THREADS = -1;
+  public static int SQLITE_MAX_WORKER_THREADS = -1;
+
+  // open flags
+  public static final int SQLITE_OPEN_READONLY = 1;
+  public static final int SQLITE_OPEN_READWRITE = 2;
+  public static final int SQLITE_OPEN_CREATE = 4;
+  public static final int SQLITE_OPEN_URI = 64;
+  public static final int SQLITE_OPEN_MEMORY = 128;
+  public static final int SQLITE_OPEN_NOMUTEX = 32768;
+  public static final int SQLITE_OPEN_FULLMUTEX = 65536;
+  public static final int SQLITE_OPEN_SHAREDCACHE = 131072;
+  public static final int SQLITE_OPEN_PRIVATECACHE = 262144;
+  public static final int SQLITE_OPEN_EXRESCODE = 33554432;
+  public static final int SQLITE_OPEN_NOFOLLOW = 16777216;
+  public static final int SQLITE_OPEN_MAIN_DB = 256;
+  public static final int SQLITE_OPEN_MAIN_JOURNAL = 2048;
+  public static final int SQLITE_OPEN_TEMP_DB = 512;
+  public static final int SQLITE_OPEN_TEMP_JOURNAL = 4096;
+  public static final int SQLITE_OPEN_TRANSIENT_DB = 1024;
+  public static final int SQLITE_OPEN_SUBJOURNAL = 8192;
+  public static final int SQLITE_OPEN_SUPER_JOURNAL = 16384;
+  public static final int SQLITE_OPEN_WAL = 524288;
+  public static final int SQLITE_OPEN_DELETEONCLOSE = 8;
+  public static final int SQLITE_OPEN_EXCLUSIVE = 16;
+
+  // prepare flags
+  public static final int SQLITE_PREPARE_PERSISTENT = 1;
+  public static final int SQLITE_PREPARE_NORMALIZE = 2;
+  public static final int SQLITE_PREPARE_NO_VTAB = 4;
+
+  // result codes
+  public static final int SQLITE_OK = 0;
+  public static final int SQLITE_ERROR = 1;
+  public static final int SQLITE_INTERNAL = 2;
+  public static final int SQLITE_PERM = 3;
+  public static final int SQLITE_ABORT = 4;
+  public static final int SQLITE_BUSY = 5;
+  public static final int SQLITE_LOCKED = 6;
+  public static final int SQLITE_NOMEM = 7;
+  public static final int SQLITE_READONLY = 8;
+  public static final int SQLITE_INTERRUPT = 9;
+  public static final int SQLITE_IOERR = 10;
+  public static final int SQLITE_CORRUPT = 11;
+  public static final int SQLITE_NOTFOUND = 12;
+  public static final int SQLITE_FULL = 13;
+  public static final int SQLITE_CANTOPEN = 14;
+  public static final int SQLITE_PROTOCOL = 15;
+  public static final int SQLITE_EMPTY = 16;
+  public static final int SQLITE_SCHEMA = 17;
+  public static final int SQLITE_TOOBIG = 18;
+  public static final int SQLITE_CONSTRAINT = 19;
+  public static final int SQLITE_MISMATCH = 20;
+  public static final int SQLITE_MISUSE = 21;
+  public static final int SQLITE_NOLFS = 22;
+  public static final int SQLITE_AUTH = 23;
+  public static final int SQLITE_FORMAT = 24;
+  public static final int SQLITE_RANGE = 25;
+  public static final int SQLITE_NOTADB = 26;
+  public static final int SQLITE_NOTICE = 27;
+  public static final int SQLITE_WARNING = 28;
+  public static final int SQLITE_ROW = 100;
+  public static final int SQLITE_DONE = 101;
+  public static final int SQLITE_ERROR_MISSING_COLLSEQ = 257;
+  public static final int SQLITE_ERROR_RETRY = 513;
+  public static final int SQLITE_ERROR_SNAPSHOT = 769;
+  public static final int SQLITE_IOERR_READ = 266;
+  public static final int SQLITE_IOERR_SHORT_READ = 522;
+  public static final int SQLITE_IOERR_WRITE = 778;
+  public static final int SQLITE_IOERR_FSYNC = 1034;
+  public static final int SQLITE_IOERR_DIR_FSYNC = 1290;
+  public static final int SQLITE_IOERR_TRUNCATE = 1546;
+  public static final int SQLITE_IOERR_FSTAT = 1802;
+  public static final int SQLITE_IOERR_UNLOCK = 2058;
+  public static final int SQLITE_IOERR_RDLOCK = 2314;
+  public static final int SQLITE_IOERR_DELETE = 2570;
+  public static final int SQLITE_IOERR_BLOCKED = 2826;
+  public static final int SQLITE_IOERR_NOMEM = 3082;
+  public static final int SQLITE_IOERR_ACCESS = 3338;
+  public static final int SQLITE_IOERR_CHECKRESERVEDLOCK = 3594;
+  public static final int SQLITE_IOERR_LOCK = 3850;
+  public static final int SQLITE_IOERR_CLOSE = 4106;
+  public static final int SQLITE_IOERR_DIR_CLOSE = 4362;
+  public static final int SQLITE_IOERR_SHMOPEN = 4618;
+  public static final int SQLITE_IOERR_SHMSIZE = 4874;
+  public static final int SQLITE_IOERR_SHMLOCK = 5130;
+  public static final int SQLITE_IOERR_SHMMAP = 5386;
+  public static final int SQLITE_IOERR_SEEK = 5642;
+  public static final int SQLITE_IOERR_DELETE_NOENT = 5898;
+  public static final int SQLITE_IOERR_MMAP = 6154;
+  public static final int SQLITE_IOERR_GETTEMPPATH = 6410;
+  public static final int SQLITE_IOERR_CONVPATH = 6666;
+  public static final int SQLITE_IOERR_VNODE = 6922;
+  public static final int SQLITE_IOERR_AUTH = 7178;
+  public static final int SQLITE_IOERR_BEGIN_ATOMIC = 7434;
+  public static final int SQLITE_IOERR_COMMIT_ATOMIC = 7690;
+  public static final int SQLITE_IOERR_ROLLBACK_ATOMIC = 7946;
+  public static final int SQLITE_IOERR_DATA = 8202;
+  public static final int SQLITE_IOERR_CORRUPTFS = 8458;
+  public static final int SQLITE_LOCKED_SHAREDCACHE = 262;
+  public static final int SQLITE_LOCKED_VTAB = 518;
+  public static final int SQLITE_BUSY_RECOVERY = 261;
+  public static final int SQLITE_BUSY_SNAPSHOT = 517;
+  public static final int SQLITE_BUSY_TIMEOUT = 773;
+  public static final int SQLITE_CANTOPEN_NOTEMPDIR = 270;
+  public static final int SQLITE_CANTOPEN_ISDIR = 526;
+  public static final int SQLITE_CANTOPEN_FULLPATH = 782;
+  public static final int SQLITE_CANTOPEN_CONVPATH = 1038;
+  public static final int SQLITE_CANTOPEN_SYMLINK = 1550;
+  public static final int SQLITE_CORRUPT_VTAB = 267;
+  public static final int SQLITE_CORRUPT_SEQUENCE = 523;
+  public static final int SQLITE_CORRUPT_INDEX = 779;
+  public static final int SQLITE_READONLY_RECOVERY = 264;
+  public static final int SQLITE_READONLY_CANTLOCK = 520;
+  public static final int SQLITE_READONLY_ROLLBACK = 776;
+  public static final int SQLITE_READONLY_DBMOVED = 1032;
+  public static final int SQLITE_READONLY_CANTINIT = 1288;
+  public static final int SQLITE_READONLY_DIRECTORY = 1544;
+  public static final int SQLITE_ABORT_ROLLBACK = 516;
+  public static final int SQLITE_CONSTRAINT_CHECK = 275;
+  public static final int SQLITE_CONSTRAINT_COMMITHOOK = 531;
+  public static final int SQLITE_CONSTRAINT_FOREIGNKEY = 787;
+  public static final int SQLITE_CONSTRAINT_FUNCTION = 1043;
+  public static final int SQLITE_CONSTRAINT_NOTNULL = 1299;
+  public static final int SQLITE_CONSTRAINT_PRIMARYKEY = 1555;
+  public static final int SQLITE_CONSTRAINT_TRIGGER = 1811;
+  public static final int SQLITE_CONSTRAINT_UNIQUE = 2067;
+  public static final int SQLITE_CONSTRAINT_VTAB = 2323;
+  public static final int SQLITE_CONSTRAINT_ROWID = 2579;
+  public static final int SQLITE_CONSTRAINT_PINNED = 2835;
+  public static final int SQLITE_CONSTRAINT_DATATYPE = 3091;
+  public static final int SQLITE_NOTICE_RECOVER_WAL = 283;
+  public static final int SQLITE_NOTICE_RECOVER_ROLLBACK = 539;
+  public static final int SQLITE_WARNING_AUTOINDEX = 284;
+  public static final int SQLITE_AUTH_USER = 279;
+  public static final int SQLITE_OK_LOAD_PERMANENTLY = 256;
+
+  // serialize
+  public static final int SQLITE_SERIALIZE_NOCOPY = 1;
+  public static final int SQLITE_DESERIALIZE_FREEONCLOSE = 1;
+  public static final int SQLITE_DESERIALIZE_READONLY = 4;
+  public static final int SQLITE_DESERIALIZE_RESIZEABLE = 2;
+
+  // session
+  public static final int SQLITE_SESSION_CONFIG_STRMSIZE = 1;
+  public static final int SQLITE_SESSION_OBJCONFIG_SIZE = 1;
+
+  // sqlite3 status
+  public static final int SQLITE_STATUS_MEMORY_USED = 0;
+  public static final int SQLITE_STATUS_PAGECACHE_USED = 1;
+  public static final int SQLITE_STATUS_PAGECACHE_OVERFLOW = 2;
+  public static final int SQLITE_STATUS_MALLOC_SIZE = 5;
+  public static final int SQLITE_STATUS_PARSER_STACK = 6;
+  public static final int SQLITE_STATUS_PAGECACHE_SIZE = 7;
+  public static final int SQLITE_STATUS_MALLOC_COUNT = 9;
+
+  // stmt status
+  public static final int SQLITE_STMTSTATUS_FULLSCAN_STEP = 1;
+  public static final int SQLITE_STMTSTATUS_SORT = 2;
+  public static final int SQLITE_STMTSTATUS_AUTOINDEX = 3;
+  public static final int SQLITE_STMTSTATUS_VM_STEP = 4;
+  public static final int SQLITE_STMTSTATUS_REPREPARE = 5;
+  public static final int SQLITE_STMTSTATUS_RUN = 6;
+  public static final int SQLITE_STMTSTATUS_FILTER_MISS = 7;
+  public static final int SQLITE_STMTSTATUS_FILTER_HIT = 8;
+  public static final int SQLITE_STMTSTATUS_MEMUSED = 99;
+
+  // sync flags
+  public static final int SQLITE_SYNC_NORMAL = 2;
+  public static final int SQLITE_SYNC_FULL = 3;
+  public static final int SQLITE_SYNC_DATAONLY = 16;
+
+  // tracing flags
+  public static final int SQLITE_TRACE_STMT = 1;
+  public static final int SQLITE_TRACE_PROFILE = 2;
+  public static final int SQLITE_TRACE_ROW = 4;
+  public static final int SQLITE_TRACE_CLOSE = 8;
+
+  // transaction state
+  public static final int SQLITE_TXN_NONE = 0;
+  public static final int SQLITE_TXN_READ = 1;
+  public static final int SQLITE_TXN_WRITE = 2;
+
+  // udf flags
+  public static final int SQLITE_DETERMINISTIC = 2048;
+  public static final int SQLITE_DIRECTONLY = 524288;
+  public static final int SQLITE_INNOCUOUS = 2097152;
+
+  // virtual tables
+  public static final int SQLITE_INDEX_SCAN_UNIQUE = 1;
+  public static final int SQLITE_INDEX_CONSTRAINT_EQ = 2;
+  public static final int SQLITE_INDEX_CONSTRAINT_GT = 4;
+  public static final int SQLITE_INDEX_CONSTRAINT_LE = 8;
+  public static final int SQLITE_INDEX_CONSTRAINT_LT = 16;
+  public static final int SQLITE_INDEX_CONSTRAINT_GE = 32;
+  public static final int SQLITE_INDEX_CONSTRAINT_MATCH = 64;
+  public static final int SQLITE_INDEX_CONSTRAINT_LIKE = 65;
+  public static final int SQLITE_INDEX_CONSTRAINT_GLOB = 66;
+  public static final int SQLITE_INDEX_CONSTRAINT_REGEXP = 67;
+  public static final int SQLITE_INDEX_CONSTRAINT_NE = 68;
+  public static final int SQLITE_INDEX_CONSTRAINT_ISNOT = 69;
+  public static final int SQLITE_INDEX_CONSTRAINT_ISNOTNULL = 70;
+  public static final int SQLITE_INDEX_CONSTRAINT_ISNULL = 71;
+  public static final int SQLITE_INDEX_CONSTRAINT_IS = 72;
+  public static final int SQLITE_INDEX_CONSTRAINT_LIMIT = 73;
+  public static final int SQLITE_INDEX_CONSTRAINT_OFFSET = 74;
+  public static final int SQLITE_INDEX_CONSTRAINT_FUNCTION = 150;
+  public static final int SQLITE_VTAB_CONSTRAINT_SUPPORT = 1;
+  public static final int SQLITE_VTAB_INNOCUOUS = 2;
+  public static final int SQLITE_VTAB_DIRECTONLY = 3;
+  public static final int SQLITE_VTAB_USES_ALL_SCHEMAS = 4;
+  public static final int SQLITE_ROLLBACK = 1;
+  public static final int SQLITE_FAIL = 3;
+  public static final int SQLITE_REPLACE = 5;
+  static {
+    // This MUST come after the SQLITE_MAX_... values or else
+    // attempting to modify them silently fails.
+    init(new SQLite3Jni());
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java
new file mode 100644 (file)
index 0000000..910fc85
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains a set of tests for the sqlite3 JNI bindings.
+** They make heavy use of assert(), so must be run with java's -ea
+** (enble assert) flag.
+*/
+package org.sqlite.jni;
+import static org.sqlite.jni.SQLite3Jni.*;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+public class Tester1 {
+
+  private static <T> void out(T val){
+    System.out.print(val);
+  }
+
+  private static <T> void outln(T val){
+    System.out.println(val);
+  }
+
+  private static int assertCount = 0;
+  private static void myassert(Boolean v){
+    ++assertCount;
+    assert( v );
+  }
+
+  private static void test1(){
+    outln("libversion_number: "
+          + sqlite3_libversion_number()
+          + "\n"
+          + sqlite3_libversion()
+          + "\n"
+          + SQLITE_SOURCE_ID);
+    myassert(sqlite3_libversion_number() == SQLITE_VERSION_NUMBER);
+    //outln("threadsafe = "+sqlite3_threadsafe());
+    myassert(SQLITE_MAX_LENGTH > 0);
+    myassert(SQLITE_MAX_TRIGGER_DEPTH>0);
+  }
+
+  private static void testCompileOption(){
+    int i = 0;
+    String optName;
+    outln("compile options:");
+    for( ; null != (optName = sqlite3_compileoption_get(i)); ++i){
+      outln("\t"+optName+"\t (used="+
+            sqlite3_compileoption_used(optName)+")");
+    }
+
+  }
+
+  private static void execSql(sqlite3 db, String[] sql){
+    execSql(db, String.join("", sql));
+  }
+  private static void execSql(sqlite3 db, String sql){
+      OutputPointer.Int32 oTail = new OutputPointer.Int32();
+      final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
+      int pos = 0, n = 1;
+      byte[] sqlChunk = sqlUtf8;
+      sqlite3_stmt stmt = new sqlite3_stmt();
+      while(pos < sqlChunk.length){
+        if(pos > 0){
+          sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
+                                        sqlChunk.length);
+        }
+        if( 0==sqlChunk.length ) break;
+        int rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail);
+        myassert(0 == rc);
+        pos = oTail.getValue();
+        myassert(0 != stmt.getNativePointer());
+        rc = sqlite3_step(stmt);
+        sqlite3_finalize(stmt);
+        myassert(0 == stmt.getNativePointer());
+        if(0!=rc && SQLITE_ROW!=rc && SQLITE_DONE!=rc){
+          throw new RuntimeException("db op failed with rc="+rc);
+        }
+      }
+  }
+  private static void testOpenDb1(){
+      sqlite3 db = new sqlite3();
+      myassert(0 == db.getNativePointer());
+      int rc = sqlite3_open(":memory:", db);
+      myassert(0 == rc);
+      myassert(0 < db.getNativePointer());
+      sqlite3_close(db);
+      myassert(0 == db.getNativePointer());
+  }
+
+  private static void testOpenDb2(){
+    sqlite3 db = new sqlite3();
+    myassert(0 == db.getNativePointer());
+    int rc = sqlite3_open_v2(":memory:", db,
+                             SQLITE_OPEN_READWRITE
+                             | SQLITE_OPEN_CREATE, null);
+    myassert(0 == rc);
+    myassert(0 < db.getNativePointer());
+    sqlite3_close_v2(db);
+    myassert(0 == db.getNativePointer());
+  }
+
+  private static sqlite3 createNewDb(){
+    sqlite3 db = new sqlite3();
+    myassert(0 == db.getNativePointer());
+    int rc = sqlite3_open(":memory:", db);
+    myassert(0 == rc);
+    myassert(0 != db.getNativePointer());
+    rc = sqlite3_busy_timeout(db, 2000);
+    myassert( 0 == rc );
+    return db;
+  }
+
+  private static void testPrepare123(){
+    sqlite3 db = createNewDb();
+    int rc;
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    myassert(0 == stmt.getNativePointer());
+    rc = sqlite3_prepare(db, "CREATE TABLE t1(a);", stmt);
+    myassert(0 == rc);
+    myassert(0 != stmt.getNativePointer());
+    rc = sqlite3_step(stmt);
+    myassert(SQLITE_DONE == rc);
+    sqlite3_finalize(stmt);
+    myassert(0 == stmt.getNativePointer());
+
+    { /* Demonstrate how to use the "zTail" option of
+         sqlite3_prepare() family of functions. */
+      OutputPointer.Int32 oTail = new OutputPointer.Int32();
+      final byte[] sqlUtf8 =
+        "CREATE TABLE t2(a); INSERT INTO t2(a) VALUES(1),(2),(3)"
+        .getBytes(StandardCharsets.UTF_8);
+      int pos = 0, n = 1;
+      byte[] sqlChunk = sqlUtf8;
+      while(pos < sqlChunk.length){
+        if(pos > 0){
+          sqlChunk = Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length);
+        }
+        //outln("SQL chunk #"+n+" length = "+sqlChunk.length+", pos = "+pos);
+        if( 0==sqlChunk.length ) break;
+        rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail);
+        myassert(0 == rc);
+        pos = oTail.getValue();
+        /*outln("SQL tail pos = "+pos+". Chunk = "+
+              (new String(Arrays.copyOfRange(sqlChunk,0,pos),
+              StandardCharsets.UTF_8)));*/
+        switch(n){
+          case 1: myassert(19 == pos); break;
+          case 2: myassert(36 == pos); break;
+          default: myassert( false /* can't happen */ );
+
+        }
+        ++n;
+        myassert(0 != stmt.getNativePointer());
+        rc = sqlite3_step(stmt);
+        myassert(SQLITE_DONE == rc);
+        sqlite3_finalize(stmt);
+        myassert(0 == stmt.getNativePointer());
+      }
+    }
+
+
+    rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)",
+                            SQLITE_PREPARE_NORMALIZE, stmt);
+    myassert(0 == rc);
+    myassert(0 != stmt.getNativePointer());
+    sqlite3_finalize(stmt);
+    myassert(0 == stmt.getNativePointer() );
+    sqlite3_close_v2(db);
+  }
+
+  private static void testBindFetchInt(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a)");
+
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(:a);", stmt);
+    myassert(0 == rc);
+    myassert(1 == sqlite3_bind_parameter_count(stmt));
+    final int paramNdx = sqlite3_bind_parameter_index(stmt, ":a");
+    myassert(1 == paramNdx);
+    int total1 = 0;
+    long rowid = -1;
+    int changes = sqlite3_changes(db);
+    int changesT = sqlite3_total_changes(db);
+    long changes64 = sqlite3_changes64(db);
+    long changesT64 = sqlite3_total_changes64(db);
+    for(int i = 99; i < 102; ++i ){
+      total1 += i;
+      rc = sqlite3_bind_int(stmt, paramNdx, i);
+      myassert(0 == rc);
+      rc = sqlite3_step(stmt);
+      sqlite3_reset(stmt);
+      myassert(SQLITE_DONE == rc);
+      long x = sqlite3_last_insert_rowid(db);
+      myassert(x > rowid);
+      rowid = x;
+    }
+    sqlite3_finalize(stmt);
+    myassert(total1 > 0);
+    myassert(sqlite3_changes(db) > changes);
+    myassert(sqlite3_total_changes(db) > changesT);
+    myassert(sqlite3_changes64(db) > changes64);
+    myassert(sqlite3_total_changes64(db) > changesT64);
+    rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
+    myassert(0 == rc);
+    int total2 = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      total2 += sqlite3_column_int(stmt, 0);
+      sqlite3_value sv = sqlite3_column_value(stmt, 0);
+      myassert( null != sv );
+      myassert( 0 != sv.getNativePointer() );
+      myassert( SQLITE_INTEGER == sqlite3_value_type(sv) );
+    }
+    sqlite3_finalize(stmt);
+    myassert(total1 == total2);
+    sqlite3_close_v2(db);
+    myassert(0 == db.getNativePointer());
+  }
+
+  private static void testBindFetchInt64(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a)");
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
+    long total1 = 0;
+    for(long i = 0xffffffff; i < 0xffffffff + 3; ++i ){
+      total1 += i;
+      sqlite3_bind_int64(stmt, 1, i);
+      sqlite3_step(stmt);
+      sqlite3_reset(stmt);
+    }
+    sqlite3_finalize(stmt);
+    rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
+    myassert(0 == rc);
+    long total2 = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      total2 += sqlite3_column_int64(stmt, 0);
+    }
+    sqlite3_finalize(stmt);
+    myassert(total1 == total2);
+    sqlite3_close_v2(db);
+  }
+
+  private static void testBindFetchDouble(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a)");
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
+    double total1 = 0;
+    for(double i = 1.5; i < 5.0; i = i + 1.0 ){
+      total1 += i;
+      sqlite3_bind_double(stmt, 1, i);
+      sqlite3_step(stmt);
+      sqlite3_reset(stmt);
+    }
+    sqlite3_finalize(stmt);
+    rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
+    myassert(0 == rc);
+    double total2 = 0;
+    int counter = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      ++counter;
+      total2 += sqlite3_column_double(stmt, 0);
+    }
+    myassert(4 == counter);
+    sqlite3_finalize(stmt);
+    myassert(total2<=total1+0.01 && total2>=total1-0.01);
+    sqlite3_close_v2(db);
+  }
+
+  private static void testBindFetchText(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a)");
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
+    String list1[] = { "hell🤩", "w😃rld", "!" };
+    for( String e : list1 ){
+      rc = sqlite3_bind_text(stmt, 1, e);
+      myassert(0 == rc);
+      rc = sqlite3_step(stmt);
+      myassert(SQLITE_DONE==rc);
+      sqlite3_reset(stmt);
+    }
+    sqlite3_finalize(stmt);
+    rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
+    myassert(0 == rc);
+    StringBuffer sbuf = new StringBuffer();
+    int n = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      String txt = sqlite3_column_text(stmt, 0);
+      //outln("txt = "+txt);
+      sbuf.append( txt );
+      ++n;
+    }
+    sqlite3_finalize(stmt);
+    myassert(3 == n);
+    myassert("w😃rldhell🤩!".equals(sbuf.toString()));
+    sqlite3_close_v2(db);
+  }
+
+  private static void testBindFetchBlob(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a)");
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
+    byte list1[] = { 0x32, 0x33, 0x34 };
+    rc = sqlite3_bind_blob(stmt, 1, list1);
+    rc = sqlite3_step(stmt);
+    myassert(SQLITE_DONE == rc);
+    sqlite3_finalize(stmt);
+    rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
+    myassert(0 == rc);
+    int n = 0;
+    int total = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      byte blob[] = sqlite3_column_blob(stmt, 0);
+      myassert(3 == blob.length);
+      int i = 0;
+      for(byte b : blob){
+        myassert(b == list1[i++]);
+        total += b;
+      }
+      ++n;
+    }
+    sqlite3_finalize(stmt);
+    myassert(1 == n);
+    myassert(total == 0x32 + 0x33 + 0x34);
+    sqlite3_close_v2(db);
+  }
+
+  private static void testCollation(){
+    sqlite3 db = createNewDb();
+    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+    final ValueHolder<Boolean> xDestroyCalled = new ValueHolder<>(false);
+    final Collation myCollation = new Collation() {
+        private String myState =
+          "this is local state. There is much like it, but this is mine.";
+        @Override
+        // Reverse-sorts its inputs...
+        public int xCompare(byte[] lhs, byte[] rhs){
+          int len = lhs.length > rhs.length ? rhs.length : lhs.length;
+          int c = 0, i = 0;
+          for(i = 0; i < len; ++i){
+            c = lhs[i] - rhs[i];
+            if(0 != c) break;
+          }
+          if(0==c){
+            if(i < lhs.length) c = 1;
+            else if(i < rhs.length) c = -1;
+          }
+          return -c;
+        }
+        @Override
+        public void xDestroy() {
+          // Just demonstrates that xDestroy is called.
+          xDestroyCalled.value = true;
+        }
+      };
+    int rc = sqlite3_create_collation(db, "reversi", SQLITE_UTF8, myCollation);
+    myassert(0 == rc);
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    sqlite3_prepare(db, "SELECT a FROM t ORDER BY a COLLATE reversi", stmt);
+    int counter = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      final String val = sqlite3_column_text(stmt, 0);
+      ++counter;
+      //outln("REVERSI'd row#"+counter+": "+val);
+      switch(counter){
+        case 1: myassert("c".equals(val)); break;
+        case 2: myassert("b".equals(val)); break;
+        case 3: myassert("a".equals(val)); break;
+      }
+    }
+    myassert(3 == counter);
+    sqlite3_finalize(stmt);
+    sqlite3_prepare(db, "SELECT a FROM t ORDER BY a", stmt);
+    counter = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      final String val = sqlite3_column_text(stmt, 0);
+      ++counter;
+      //outln("Non-REVERSI'd row#"+counter+": "+val);
+      switch(counter){
+        case 3: myassert("c".equals(val)); break;
+        case 2: myassert("b".equals(val)); break;
+        case 1: myassert("a".equals(val)); break;
+      }
+    }
+    myassert(3 == counter);
+    sqlite3_finalize(stmt);
+    myassert(!xDestroyCalled.value);
+    sqlite3_close(db);
+    myassert(xDestroyCalled.value);
+  }
+
+  private static void testToUtf8(){
+    /**
+       Java docs seem contradictory, claiming to use "modified UTF-8"
+       encoding while also claiming to export using RFC 2279:
+
+       https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html
+    */
+    final byte[] ba = "a \0 b".getBytes(StandardCharsets.UTF_8);
+    //out("\"a NUL b\" via getBytes(): ");
+    myassert( 5 == ba.length /* as opposed to 6 in modified utf-8 */);
+    //for( byte b : ba ) out( ""+b );
+    //outln("");
+  }
+
+  private static void testUdf1(){
+    final sqlite3 db = createNewDb();
+    // These ValueHolders are just to confirm that the func did what we want...
+    final ValueHolder<Boolean> xDestroyCalled = new ValueHolder<>(false);
+    final ValueHolder<Integer> xFuncAccum = new ValueHolder<>(0);
+
+    // Create an SQLFunction instance using one of its 3 subclasses:
+    // Scalar, Aggregate, or Window:
+    SQLFunction func =
+      // Each of the 3 subclasses requires a different set of
+      // functions, all of which must be implemented.  Anonymous
+      // classes are a convenient way to implement these, though the
+      // result is possibly somewhat noisy for those not at home in
+      // Java...
+      new SQLFunction.Scalar(){
+        public void xFunc(sqlite3_context cx, sqlite3_value args[]){
+          myassert(db.getNativePointer()
+                   == sqlite3_context_db_handle(cx).getNativePointer());
+          int result = 0;
+          for( sqlite3_value v : args ) result += sqlite3_value_int(v);
+          xFuncAccum.value += result;// just for post-run testing
+          sqlite3_result_int(cx, result);
+        }
+        /* OPTIONALLY override xDestroy... */
+        public void xDestroy(){
+          xDestroyCalled.value = true;
+        }
+      };
+
+    // Register and use the function...
+    int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
+    assert(0 == rc);
+    assert(0 == xFuncAccum.value);
+    execSql(db, "SELECT myfunc(1,2,3)");
+    assert(6 == xFuncAccum.value);
+    assert( !xDestroyCalled.value );
+    sqlite3_close(db);
+    assert( xDestroyCalled.value );
+  }
+
+  private static void testUdfJavaObject(){
+    final sqlite3 db = createNewDb();
+    final ValueHolder<Long> testResult = new ValueHolder<>(42L);
+    SQLFunction func = new SQLFunction.Scalar(){
+        public void xFunc(sqlite3_context cx, sqlite3_value args[]){
+          sqlite3_result_java_object(cx, testResult.value);
+        }
+      };
+    int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
+    assert(0 == rc);
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    sqlite3_prepare(db, "select myfunc()", stmt);
+    assert( 0 != stmt.getNativePointer() );
+    int n = 0;
+    if( SQLITE_ROW == sqlite3_step(stmt) ){
+      sqlite3_value v = sqlite3_column_value(stmt, 0);
+      assert( testResult.value == sqlite3_value_java_object(v) );
+      assert( testResult.value == sqlite3_value_java_casted(v, Long.class) );
+      assert( testResult.value ==
+              sqlite3_value_java_casted(v, testResult.value.getClass()) );
+      assert( null == sqlite3_value_java_casted(v, Double.class) );
+      ++n;
+    }
+    sqlite3_finalize(stmt);
+    assert( 1 == n );
+    sqlite3_close(db);
+  }
+
+  private static void testUdfAggregate(){
+    final sqlite3 db = createNewDb();
+    SQLFunction func = new SQLFunction.Aggregate(){
+        private int accum = 0;
+        @Override public void xStep(sqlite3_context cx, sqlite3_value args[]){
+          this.accum += sqlite3_value_int(args[0]);
+        }
+        @Override public void xFinal(sqlite3_context cx){
+          sqlite3_result_int(cx, this.accum);
+          this.accum = 0;
+        }
+      };
+    execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES(1),(2),(3)");
+    int rc = sqlite3_create_function(db, "myfunc", 1, SQLITE_UTF8, func);
+    assert(0 == rc);
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    sqlite3_prepare(db, "select myfunc(a) from t", stmt);
+    assert( 0 != stmt.getNativePointer() );
+    int n = 0;
+    if( SQLITE_ROW == sqlite3_step(stmt) ){
+      final int v = sqlite3_column_int(stmt, 0);
+      myassert( 6 == v );
+      ++n;
+    }
+    sqlite3_reset(stmt);
+    // Ensure that the accumulator is reset...
+    n = 0;
+    if( SQLITE_ROW == sqlite3_step(stmt) ){
+      final int v = sqlite3_column_int(stmt, 0);
+      myassert( 6 == v );
+      ++n;
+    }
+    sqlite3_finalize(stmt);
+    assert( 1==n );
+    sqlite3_close(db);
+  }
+
+  private static void testUdfWindow(){
+    final sqlite3 db = createNewDb();
+    /* Example window function, table, and results taken from:
+       https://sqlite.org/windowfunctions.html#udfwinfunc */
+    final SQLFunction func = new SQLFunction.Window(){
+        private int accum = 0;
+        private void xStepInverse(int v){
+          this.accum += v;
+        }
+        private void xFinalValue(sqlite3_context cx){
+          sqlite3_result_int(cx, this.accum);
+        }
+        @Override public void xStep(sqlite3_context cx, sqlite3_value[] args){
+          this.xStepInverse(sqlite3_value_int(args[0]));
+        }
+        @Override public void xInverse(sqlite3_context cx, sqlite3_value[] args){
+          this.xStepInverse(-sqlite3_value_int(args[0]));
+        }
+        @Override public void xFinal(sqlite3_context cx){
+          this.xFinalValue(cx);
+          this.accum = 0;
+        }
+        @Override public void xValue(sqlite3_context cx){
+          this.xFinalValue(cx);
+        }
+      };
+    int rc = sqlite3_create_function(db, "winsumint", 1, SQLITE_UTF8, func);
+    myassert( 0 == rc );
+    execSql(db, new String[] {
+        "CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
+        "('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
+      });
+    sqlite3_stmt stmt = new sqlite3_stmt();
+    rc = sqlite3_prepare(db,
+                         "SELECT x, winsumint(y) OVER ("+
+                         "ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
+                         ") AS sum_y "+
+                         "FROM twin ORDER BY x;", stmt);
+    myassert( 0 == rc );
+    int n = 0;
+    while( SQLITE_ROW == sqlite3_step(stmt) ){
+      final String s = sqlite3_column_text(stmt, 0);
+      final int i = sqlite3_column_int(stmt, 1);
+      switch(++n){
+        case 1: myassert( "a".equals(s) && 9==i ); break;
+        case 2: myassert( "b".equals(s) && 12==i ); break;
+        case 3: myassert( "c".equals(s) && 16==i ); break;
+        case 4: myassert( "d".equals(s) && 12==i ); break;
+        case 5: myassert( "e".equals(s) && 9==i ); break;
+        default: myassert( false /* cannot happen */ );
+      }
+    }
+    sqlite3_finalize(stmt);
+    myassert( 5 == n );
+    sqlite3_close(db);
+  }
+
+  private static void listBoundMethods(){
+    //public static List<Field> getStatics(Class<?> clazz) {
+    if(false){
+      final java.lang.reflect.Field[] declaredFields =
+        SQLite3Jni.class.getDeclaredFields();
+      outln("Bound constants:\n");
+      for(java.lang.reflect.Field field : declaredFields) {
+        if(java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
+          outln("\t"+field.getName());
+        }
+      }
+    }
+    final java.lang.reflect.Method[] declaredMethods =
+      SQLite3Jni.class.getDeclaredMethods();
+    final java.util.List<String> funcList = new java.util.ArrayList<>();
+    for(java.lang.reflect.Method m : declaredMethods){
+      if((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0){
+        final String name = m.getName();
+        if(name.startsWith("sqlite3_")){
+          funcList.add(name);
+        }
+      }
+    }
+    int count = 0;
+    java.util.Collections.sort(funcList);
+    for(String n : funcList){
+      ++count;
+      outln("\t"+n+"()");
+    }
+    outln(count+" functions named sqlite3_*.");
+  }
+
+  private static void testTrace(){
+    final sqlite3 db = createNewDb();
+    final ValueHolder<Integer> counter = new ValueHolder<>(0);
+    sqlite3_trace_v2(
+      db, SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE
+          | SQLITE_TRACE_ROW | SQLITE_TRACE_CLOSE,
+      new Tracer(){
+        public int xCallback(int traceFlag, long pNative, Object x){
+          ++counter.value;
+          //outln("Trace #"+counter.value+" flag="+traceFlag+": "+x);
+          switch(traceFlag){
+            case SQLITE_TRACE_STMT:
+              // pNative ==> sqlite3_stmt
+              myassert(x instanceof String); break;
+            case SQLITE_TRACE_PROFILE:
+              // pNative ==> sqlite3_stmt
+              myassert(x instanceof Long); break;
+            case SQLITE_TRACE_ROW:
+              // pNative ==> sqlite3_stmt
+            case SQLITE_TRACE_CLOSE:
+              // pNative ==> sqlite3
+              myassert(null == x);
+          }
+          return 0;
+        }
+      });
+    execSql(db, "SELECT 1; SELECT 2");
+    myassert( 6 == counter.value );
+    sqlite3_close(db);
+    myassert( 7 == counter.value );
+  }
+
+  private static void testMisc(){
+    outln("Sleeping...");
+    sqlite3_sleep(500);
+    outln("Woke up.");
+  }
+
+  public static void main(String[] args){
+    test1();
+    if(false) testCompileOption();
+    final java.util.List<String> liArgs =
+      java.util.Arrays.asList(args);
+    testOpenDb1();
+    testOpenDb2();
+    testPrepare123();
+    testBindFetchInt();
+    testBindFetchInt64();
+    testBindFetchDouble();
+    testBindFetchText();
+    testBindFetchBlob();
+    testCollation();
+    testToUtf8();
+    testUdf1();
+    testUdfJavaObject();
+    testUdfAggregate();
+    testUdfWindow();
+    testTrace();
+    testMisc();
+    if(liArgs.indexOf("-v")>0){
+      listBoundMethods();
+    }
+    outln("Tests done. "+assertCount+" assertion(s) checked.");
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/Tracer.java b/ext/jni/src/org/sqlite/jni/Tracer.java
new file mode 100644 (file)
index 0000000..52ccfab
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+** 2023-07-22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   Callback proxy for use with sqlite3_trace_v2().
+*/
+public interface Tracer {
+  /**
+     Called by sqlite3 for various tracing operations, as per
+     sqlite3_trace_v2(). Note that this interface elides the 2nd
+     argument to the native trace callback, as that role is better
+     filled by instance-local state.
+
+     The 2nd argument to this function, if non-0, will be a native
+     pointer to either an sqlite3 or sqlite3_stmt object, depending on
+     the first argument (see below). Client code can pass it to the
+     sqlite3 resp. sqlite3_stmt constructor to create a wrapping
+     object, if necessary. This API does not do so by default because
+     tracing can be called frequently, creating such a wrapper for
+     each call is comparatively expensive, and the objects are
+     probably only seldom useful.
+
+     The final argument to this function is the "X" argument
+     documented for sqlite3_trace() and sqlite3_trace_v2(). Its type
+     depends on value of the first argument:
+
+     - SQLITE_TRACE_STMT: pNative is a sqlite3_stmt. pX is a string
+       containing the prepared SQL, with one caveat/FIXME: JNI only
+       provides us with the ability to convert that string to MUTF-8,
+       as opposed to standard UTF-8, and is cannot be ruled out that
+       that difference may be significant for certain inputs. The
+       alternative would be that we first convert it to UTF-16 before
+       passing it on, but there's no readily-available way to do that
+       without calling back into the db to peform the conversion
+       (which would lead to further tracing).
+
+     - SQLITE_TRACE_PROFILE: pNative is a sqlite3_stmt. pX is a Long
+       holding an approximate number of nanoseconds the statement took
+       to run.
+
+     - SQLITE_TRACE_ROW: pNative is a sqlite3_stmt. pX is null.
+
+     - SQLITE_TRACE_CLOSE: pNative is a sqlite3. pX is null.
+  */
+  int xCallback(int traceFlag, long pNative, Object pX);
+}
diff --git a/ext/jni/src/org/sqlite/jni/ValueHolder.java b/ext/jni/src/org/sqlite/jni/ValueHolder.java
new file mode 100644 (file)
index 0000000..7f6a463
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   A helper class which simply holds a single value. Its current use
+   is for communicating values out of anonymous classes, as doing so
+   requires a "final" reference.
+*/
+public class ValueHolder<T> {
+  public T value;
+  public ValueHolder(){}
+  public ValueHolder(T v){value = v;}
+}
diff --git a/ext/jni/src/org/sqlite/jni/sqlite3.java b/ext/jni/src/org/sqlite/jni/sqlite3.java
new file mode 100644 (file)
index 0000000..82bb559
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   A wrapper for communicating C-level (sqlite3*) instances with
+   Java. These wrappers do not own their associated pointer, they
+   simply provide a type-safe way to communicate it between Java
+   and C via JNI.
+*/
+public class sqlite3 extends NativePointerHolder<sqlite3> {
+  public sqlite3() {
+    super();
+  }
+  /**
+     Construct a new instance which refers to an existing
+     native (sqlite3*). The argument may be 0. Results are
+     undefined if it is not 0 and refers to a memory address
+     other than a valid (sqlite*).
+  */
+  public sqlite3(long nativePointer) {
+    super(nativePointer);
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/sqlite3_context.java b/ext/jni/src/org/sqlite/jni/sqlite3_context.java
new file mode 100644 (file)
index 0000000..9d053ff
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+public class sqlite3_context extends NativePointerHolder<sqlite3_context> {
+  public sqlite3_context() {
+    super();
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/sqlite3_stmt.java b/ext/jni/src/org/sqlite/jni/sqlite3_stmt.java
new file mode 100644 (file)
index 0000000..199689a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+   A wrapper for communicating C-level (sqlite3_stmt*) instances with
+   Java. These wrappers do not own their associated pointer, they
+   simply provide a type-safe way to communicate it between Java and C
+   via JNI.
+*/
+public class sqlite3_stmt extends NativePointerHolder<sqlite3_stmt> {
+  public sqlite3_stmt() {
+    super();
+  }
+  /**
+     Construct a new instance which refers to an existing native
+     (sqlite3_stmt*). The argument may be 0. Results are undefined if
+     it is not 0 and refers to a memory address other than a valid
+     (sqlite_stmt*).
+  */
+  public sqlite3_stmt(long nativePointer) {
+    super(nativePointer);
+  }
+}
diff --git a/ext/jni/src/org/sqlite/jni/sqlite3_value.java b/ext/jni/src/org/sqlite/jni/sqlite3_value.java
new file mode 100644 (file)
index 0000000..41347d8
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+public class sqlite3_value extends NativePointerHolder<sqlite3_value> {
+  public sqlite3_value() {
+    super();
+  }
+}
index 9173c248a56bc0dd4023d5a612a0c8f3808dd0da..21efb214a7c6d2cb2a46e871fde595eac18dcf61 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\scontentless_delete=1\soption\sto\sfts5.\sFor\screating\scontentless\stables\sthat\ssupport\sDELETE\sand\sREPLACE\sstatements.
-D 2023-07-27T19:13:35.663
+C Initial\scheck-in\sof\sJNI\s(Java\sNative\sInterface)\sbindings\sfor\sthe\score\sC\sAPI.
+D 2023-07-27T20:02:49.521
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -230,6 +230,23 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
 F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
+F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d
+F ext/jni/README.md 5ce36c6f64208a2d8e7641e7ac255400a99f378f726fa44943a008bcb403aeb0
+F ext/jni/src/c/sqlite3-jni.c 55bf5624beee849b1c063bf929e6066dc95437564c3212d30e672280bec45da8
+F ext/jni/src/c/sqlite3-jni.h ef862321bb153135472ebe6be6df9db3e47448ae3ef6bb3cb7953c54971efcf8
+F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
+F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 70dc7bc41f80352ff3d4331e2e24f45fcd23353b3641e2f68a81bd8262215861
+F ext/jni/src/org/sqlite/jni/OutputPointer.java 08a752b58a33696c5eaf0eb9361a0966b188dec40f4a3613eb133123951f6c5f
+F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5a1d7b2607eb2ef596fcf4492a49d1b3a5bdea3af9918e11716831ffd2f02284
+F ext/jni/src/org/sqlite/jni/SQLFunction.java 2f5d197f6c7d73b6031ba1a19598d7e3eee5ebad467eeee62c72e585bd6556a5
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java d588c88c17290f5b0d1e4e2a1ea68cf9acab40891c98e08203f1b90ac2aaf8dd
+F ext/jni/src/org/sqlite/jni/Tester1.java 512e545357ce1a5788b250395f2b198ae862f915aee1a8b7b8fae4620d0cfc8d
+F ext/jni/src/org/sqlite/jni/Tracer.java c2fe1eba4a76581b93b375a7b95ab1919e5ae60accfb06d6beb067b033e9bae1
+F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
+F ext/jni/src/org/sqlite/jni/sqlite3.java c7d0500c7269882243aafb41425928d094b2fcbdbc2fd1caffc276871cd3fae3
+F ext/jni/src/org/sqlite/jni/sqlite3_context.java d781c72237e4a442adf6726b2edf15124405c28eba0387a279078858700f567c
+F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 3193693440071998a66870544d1d2314f144bea397ce4c3f83ff225d587067a0
+F ext/jni/src/org/sqlite/jni/sqlite3_value.java f9d8c0766b1d1b290564cb35db8d37be54c42adc8df22ee77b8d39e3e93398cd
 F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
 F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
 F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
@@ -2049,9 +2066,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P fd59226b34fffb1479fb2d7bd7c0aff982aa4a1a73e6c0d81de6eaf9c075998c 719973d7f5a47b110e9919fcb96d21feab1e41356dbb3ec674c1116c17bbb778
-R aea8a90a4ab6b65ce2d69f610973d78d
-T +closed 719973d7f5a47b110e9919fcb96d21feab1e41356dbb3ec674c1116c17bbb778
-U dan
-Z dc969c62dd2115415f4e48c1e3d95206
+P d66b182d2bc6ce0772e69401b7affe1adbc1b128c4631cb3c17f98dde72af00a
+R 9595d1bd6387113a14191c3a678b4869
+T *branch * jni
+T *sym-jni *
+T -sym-trunk * Cancelled\sby\sbranch.
+U stephan
+Z 1ff9901b09f119a40a482027609a6cc2
 # Remove this line to create a well-formed Fossil manifest.
index 3150e0134ddca15fcf84a1fa612b23bbd6d673e0..8421cad1659daead20133e44d1527845f70a9a53 100644 (file)
@@ -1 +1 @@
-d66b182d2bc6ce0772e69401b7affe1adbc1b128c4631cb3c17f98dde72af00a
\ No newline at end of file
+b5374b9ef58fa0be80aefccde0721f5599fb820464b13940b6361b9aa09a59d5
\ No newline at end of file