summaryrefslogtreecommitdiffstats
path: root/sqlite-jdbc/src/main/native/sqlite_jni.c
diff options
context:
space:
mode:
Diffstat (limited to 'sqlite-jdbc/src/main/native/sqlite_jni.c')
-rw-r--r--sqlite-jdbc/src/main/native/sqlite_jni.c4404
1 files changed, 4404 insertions, 0 deletions
diff --git a/sqlite-jdbc/src/main/native/sqlite_jni.c b/sqlite-jdbc/src/main/native/sqlite_jni.c
new file mode 100644
index 0000000..1333d24
--- /dev/null
+++ b/sqlite-jdbc/src/main/native/sqlite_jni.c
@@ -0,0 +1,4404 @@
+#include "JNIHelp.h"
+#include "sqlite_jni_defs.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_SQLITE2
+#include "sqlite.h"
+#endif
+
+#if HAVE_SQLITE3
+#include "sqlite3.h"
+#undef HAVE_SQLITE_COMPILE
+#define HAVE_SQLITE_COMPILE 1
+#undef HAVE_SQLITE_PROGRESS_HANDLER
+#define HAVE_SQLITE_PROGRESS_HANDLER 1
+#undef HAVE_SQLITE_TRACE
+#define HAVE_SQLITE_TRACE 1
+#if !HAVE_SQLITE3_MALLOC
+#define sqlite3_malloc malloc
+#define sqlite3_free free
+#endif
+#if !HAVE_SQLITE3_BIND_PARAMETER_COUNT
+#define sqlite3_bind_parameter_count(dummy) (1000)
+#endif
+#endif
+
+#if HAVE_SQLITE2 && HAVE_SQLITE3
+#define HAVE_BOTH_SQLITE 1
+#endif
+
+#define CANT_PASS_VALIST_AS_CHARPTR
+
+#include "sqlite_jni.h"
+
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+#define MAX_PARAMS 256
+#else
+#define MAX_PARAMS 32
+#endif
+
+/* free memory proc */
+
+typedef void (freemem)(void *);
+
+/* internal handle for SQLite database */
+
+typedef struct {
+ void *sqlite; /* SQLite handle */
+#if HAVE_BOTH_SQLITE
+ int is3; /* True for SQLITE3 handle */
+#endif
+ int ver; /* version code */
+ jobject bh; /* BusyHandler object */
+ jobject cb; /* Callback object */
+ jobject ai; /* Authorizer object */
+ jobject tr; /* Trace object */
+ jobject ph; /* ProgressHandler object */
+ JNIEnv *env; /* Java environment for callbacks */
+ int row1; /* true while processing first row */
+ int haveutf; /* true for SQLite UTF-8 support */
+ jstring enc; /* encoding or 0 */
+ struct hfunc *funcs; /* SQLite user defined function handles */
+#if HAVE_SQLITE_COMPILE
+ struct hvm *vms; /* Compiled SQLite VMs */
+#endif
+#if HAVE_SQLITE3
+ sqlite3_stmt *stmt; /* For callback() */
+#endif
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ struct hbl *blobs; /* SQLite3 blob handles */
+#endif
+} handle;
+
+/* internal handle for SQLite user defined function */
+
+typedef struct hfunc {
+ struct hfunc *next; /* next function */
+#if HAVE_BOTH_SQLITE
+ int is3; /* True for SQLITE3 handle */
+#endif
+ jobject fc; /* FunctionContext object */
+ jobject fi; /* Function object */
+ jobject db; /* Database object */
+ handle *h; /* SQLite database handle */
+ void *sf; /* SQLite function handle */
+ JNIEnv *env; /* Java environment for callbacks */
+} hfunc;
+
+#if HAVE_SQLITE_COMPILE
+/* internal handle for SQLite VM (sqlite_compile()) */
+
+typedef struct hvm {
+ struct hvm *next; /* next vm handle */
+#if HAVE_BOTH_SQLITE
+ int is3; /* True for SQLITE3 handle */
+#endif
+ void *vm; /* SQLite 2/3 VM/statement */
+ char *tail; /* tail SQL string */
+ int tail_len; /* only for SQLite3/prepare */
+ handle *h; /* SQLite database handle */
+ handle hh; /* fake SQLite database handle */
+} hvm;
+#endif
+
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+/* internal handle for sqlite3_blob */
+
+typedef struct hbl {
+ struct hbl *next; /* next blob handle */
+ sqlite3_blob *blob; /* SQLite3 blob */
+ handle *h; /* SQLite database handle */
+} hbl;
+#endif
+
+/* ISO to/from UTF-8 translation */
+
+typedef struct {
+ char *result; /* translated C string result */
+ char *tofree; /* memory to be free'd, or 0 */
+ jstring jstr; /* resulting Java string or 0 */
+} transstr;
+
+/* static cached weak class refs, field and method ids */
+
+static jclass C_java_lang_String = 0;
+
+static jfieldID F_SQLite_Database_handle = 0;
+static jfieldID F_SQLite_Database_error_code = 0;
+static jfieldID F_SQLite_FunctionContext_handle = 0;
+static jfieldID F_SQLite_Vm_handle = 0;
+static jfieldID F_SQLite_Vm_error_code = 0;
+static jfieldID F_SQLite_Stmt_handle = 0;
+static jfieldID F_SQLite_Stmt_error_code = 0;
+static jfieldID F_SQLite_Blob_handle = 0;
+static jfieldID F_SQLite_Blob_size = 0;
+
+static jmethodID M_java_lang_String_getBytes = 0;
+static jmethodID M_java_lang_String_getBytes2 = 0;
+static jmethodID M_java_lang_String_initBytes = 0;
+static jmethodID M_java_lang_String_initBytes2 = 0;
+
+static const char xdigits[] = "0123456789ABCDEF";
+
+static void
+seterr(JNIEnv *env, jobject obj, int err)
+{
+ jvalue v;
+
+ v.j = 0;
+ v.i = (jint) err;
+ (*env)->SetIntField(env, obj, F_SQLite_Database_error_code, v.i);
+}
+
+#if HAVE_SQLITE_COMPILE
+static void
+setvmerr(JNIEnv *env, jobject obj, int err)
+{
+ jvalue v;
+
+ v.j = 0;
+ v.i = (jint) err;
+ (*env)->SetIntField(env, obj, F_SQLite_Vm_error_code, v.i);
+}
+
+#if HAVE_SQLITE3
+static void
+setstmterr(JNIEnv *env, jobject obj, int err)
+{
+ jvalue v;
+
+ v.j = 0;
+ v.i = (jint) err;
+ (*env)->SetIntField(env, obj, F_SQLite_Stmt_error_code, v.i);
+}
+
+static int
+jstrlen(const jchar *jstr)
+{
+ int len = 0;
+
+ if (jstr) {
+ while (*jstr++) {
+ len++;
+ }
+ }
+ return len;
+}
+#endif
+#endif
+
+static void *
+gethandle(JNIEnv *env, jobject obj)
+{
+ jvalue v;
+
+ v.j = (*env)->GetLongField(env, obj, F_SQLite_Database_handle);
+ return (void *) v.l;
+}
+
+#if HAVE_SQLITE_COMPILE
+static void *
+gethvm(JNIEnv *env, jobject obj)
+{
+ jvalue v;
+
+ v.j = (*env)->GetLongField(env, obj, F_SQLite_Vm_handle);
+ return (void *) v.l;
+}
+
+#if HAVE_SQLITE3
+static void *
+gethstmt(JNIEnv *env, jobject obj)
+{
+ jvalue v;
+
+ v.j = (*env)->GetLongField(env, obj, F_SQLite_Stmt_handle);
+ return (void *) v.l;
+}
+#endif
+#endif
+
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+static void *
+gethbl(JNIEnv *env, jobject obj)
+{
+ jvalue v;
+
+ v.j = (*env)->GetLongField(env, obj, F_SQLite_Blob_handle);
+ return (void *) v.l;
+}
+#endif
+
+static void
+delglobrefp(JNIEnv *env, jobject *obj)
+{
+ if (*obj) {
+ (*env)->DeleteGlobalRef(env, *obj);
+ *obj = 0;
+ }
+}
+
+static jobject
+globrefpop(JNIEnv *env, jobject *obj)
+{
+ jobject ret = 0;
+
+ if (*obj) {
+ ret = *obj;
+ *obj = 0;
+ }
+ return ret;
+}
+
+static void
+globrefset(JNIEnv *env, jobject obj, jobject *ref)
+{
+ if (ref) {
+ if (obj) {
+ *ref = (*env)->NewGlobalRef(env, obj);
+ } else {
+ *ref = 0;
+ }
+ }
+}
+
+static void
+freep(char **strp)
+{
+ if (strp && *strp) {
+ free(*strp);
+ *strp = 0;
+ }
+}
+
+static void
+throwex(JNIEnv *env, const char *msg)
+{
+ jclass except = (*env)->FindClass(env, "SQLite/Exception");
+
+ (*env)->ExceptionClear(env);
+ if (except) {
+ (*env)->ThrowNew(env, except, msg);
+ }
+}
+
+static void
+throwoom(JNIEnv *env, const char *msg)
+{
+ jclass except = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+
+ (*env)->ExceptionClear(env);
+ if (except) {
+ (*env)->ThrowNew(env, except, msg);
+ }
+}
+
+static void
+throwclosed(JNIEnv *env)
+{
+ throwex(env, "database already closed");
+}
+
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+static void
+throwioex(JNIEnv *env, const char *msg)
+{
+ jclass except = (*env)->FindClass(env, "java/io/IOException");
+
+ (*env)->ExceptionClear(env);
+ if (except) {
+ (*env)->ThrowNew(env, except, msg);
+ }
+}
+#endif
+
+static void
+transfree(transstr *dest)
+{
+ dest->result = 0;
+ freep(&dest->tofree);
+}
+
+static char *
+trans2iso(JNIEnv *env, int haveutf, jstring enc, jstring src,
+ transstr *dest)
+{
+ jbyteArray bytes = 0;
+ jthrowable exc;
+
+ dest->result = 0;
+ dest->tofree = 0;
+ if (haveutf) {
+ const jsize utfLength = (*env)->GetStringUTFLength(env, src);
+ dest->result = dest->tofree = malloc(utfLength + 1);
+ if (!dest->tofree) {
+ throwoom(env, "string translation failed");
+ return dest->result;
+ }
+ (*env)->GetStringUTFRegion(env, src, 0, utfLength, dest->result);
+ return dest->result;
+ }
+ if (enc) {
+ bytes = (*env)->CallObjectMethod(env, src,
+ M_java_lang_String_getBytes2, enc);
+ } else {
+ bytes = (*env)->CallObjectMethod(env, src,
+ M_java_lang_String_getBytes);
+ }
+ exc = (*env)->ExceptionOccurred(env);
+ if (!exc) {
+ jint len = (*env)->GetArrayLength(env, bytes);
+ dest->tofree = malloc(len + 1);
+ if (!dest->tofree) {
+ throwoom(env, "string translation failed");
+ return dest->result;
+ }
+ dest->result = dest->tofree;
+ (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *) dest->result);
+ dest->result[len] = '\0';
+ } else {
+ (*env)->DeleteLocalRef(env, exc);
+ }
+ return dest->result;
+}
+
+static jstring
+trans2utf(JNIEnv *env, int haveutf, jstring enc, const char *src,
+ transstr *dest)
+{
+ jbyteArray bytes = 0;
+ int len;
+
+ dest->result = 0;
+ dest->tofree = 0;
+ dest->jstr = 0;
+ if (!src) {
+ return dest->jstr;
+ }
+ if (haveutf) {
+ dest->jstr = (*env)->NewStringUTF(env, src);
+ return dest->jstr;
+ }
+ len = strlen(src);
+ bytes = (*env)->NewByteArray(env, len);
+ if (bytes) {
+ (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) src);
+ if (enc) {
+ dest->jstr =
+ (*env)->NewObject(env, C_java_lang_String,
+ M_java_lang_String_initBytes2, bytes, enc);
+ } else {
+ dest->jstr =
+ (*env)->NewObject(env, C_java_lang_String,
+ M_java_lang_String_initBytes, bytes);
+ }
+ (*env)->DeleteLocalRef(env, bytes);
+ return dest->jstr;
+ }
+ throwoom(env, "string translation failed");
+ return dest->jstr;
+}
+
+#if HAVE_SQLITE2
+static int
+busyhandler(void *udata, const char *table, int count)
+{
+ handle *h = (handle *) udata;
+ JNIEnv *env = h->env;
+ int ret = 0;
+
+ if (env && h->bh) {
+ transstr tabstr;
+ jclass cls = (*env)->GetObjectClass(env, h->bh);
+ jmethodID mid = (*env)->GetMethodID(env, cls, "busy",
+ "(Ljava/lang/String;I)Z");
+
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return ret;
+ }
+ trans2utf(env, h->haveutf, h->enc, table, &tabstr);
+ ret = (*env)->CallBooleanMethod(env, h->bh, mid, tabstr.jstr,
+ (jint) count)
+ != JNI_FALSE;
+ (*env)->DeleteLocalRef(env, tabstr.jstr);
+ (*env)->DeleteLocalRef(env, cls);
+ }
+ return ret;
+}
+#endif
+
+#if HAVE_SQLITE3
+static int
+busyhandler3(void *udata, int count)
+{
+ handle *h = (handle *) udata;
+ JNIEnv *env = h->env;
+ int ret = 0;
+
+ if (env && h->bh) {
+ jclass cls = (*env)->GetObjectClass(env, h->bh);
+ jmethodID mid = (*env)->GetMethodID(env, cls, "busy",
+ "(Ljava/lang/String;I)Z");
+
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return ret;
+ }
+ ret = (*env)->CallBooleanMethod(env, h->bh, mid, 0, (jint) count)
+ != JNI_FALSE;
+ (*env)->DeleteLocalRef(env, cls);
+ }
+ return ret;
+}
+#endif
+
+static int
+progresshandler(void *udata)
+{
+ handle *h = (handle *) udata;
+ JNIEnv *env = h->env;
+ int ret = 0;
+
+ if (env && h->ph) {
+ jclass cls = (*env)->GetObjectClass(env, h->ph);
+ jmethodID mid = (*env)->GetMethodID(env, cls, "progress", "()Z");
+
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return ret;
+ }
+ ret = (*env)->CallBooleanMethod(env, h->ph, mid) != JNI_TRUE;
+ (*env)->DeleteLocalRef(env, cls);
+ }
+ return ret;
+}
+
+static int
+callback(void *udata, int ncol, char **data, char **cols)
+{
+ handle *h = (handle *) udata;
+ JNIEnv *env = h->env;
+
+ if (env && h->cb) {
+ jthrowable exc;
+ jclass cls = (*env)->GetObjectClass(env, h->cb);
+ jmethodID mid;
+ jobjectArray arr = 0;
+ jint i;
+
+ if (h->row1) {
+ mid = (*env)->GetMethodID(env, cls, "columns",
+ "([Ljava/lang/String;)V");
+
+ if (mid) {
+ arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0);
+ for (i = 0; i < ncol; i++) {
+ if (cols[i]) {
+ transstr col;
+
+ trans2utf(env, h->haveutf, h->enc, cols[i], &col);
+ (*env)->SetObjectArrayElement(env, arr, i, col.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, col.jstr);
+ }
+ }
+ h->row1 = 0;
+ (*env)->CallVoidMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, arr);
+ }
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ mid = (*env)->GetMethodID(env, cls, "types",
+ "([Ljava/lang/String;)V");
+
+ if (mid && h->stmt) {
+ arr = (*env)->NewObjectArray(env, ncol,
+ C_java_lang_String, 0);
+ for (i = 0; i < ncol; i++) {
+ const char *ctype =
+ sqlite3_column_decltype(h->stmt, i);
+
+ if (!ctype) {
+ switch (sqlite3_column_type(h->stmt, i)) {
+ case SQLITE_INTEGER: ctype = "integer"; break;
+ case SQLITE_FLOAT: ctype = "double"; break;
+ default:
+#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT)
+ case SQLITE_TEXT:
+#else
+#ifdef SQLITE3_TEXT
+ case SQLITE3_TEXT:
+#endif
+#endif
+ ctype = "text"; break;
+ case SQLITE_BLOB: ctype = "blob"; break;
+ case SQLITE_NULL: ctype = "null"; break;
+ }
+ }
+ if (ctype) {
+ transstr ty;
+
+ trans2utf(env, 1, 0, ctype, &ty);
+ (*env)->SetObjectArrayElement(env, arr, i,
+ ty.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, ty.jstr);
+ }
+ }
+ (*env)->CallVoidMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, arr);
+ }
+ } else {
+ if (h->ver >= 0x020506 && cols[ncol]) {
+ mid = (*env)->GetMethodID(env, cls, "types",
+ "([Ljava/lang/String;)V");
+
+ if (mid) {
+ arr = (*env)->NewObjectArray(env, ncol,
+ C_java_lang_String, 0);
+ for (i = 0; i < ncol; i++) {
+ if (cols[i + ncol]) {
+ transstr ty;
+
+ trans2utf(env, h->haveutf, h->enc,
+ cols[i + ncol], &ty);
+ (*env)->SetObjectArrayElement(env, arr, i,
+ ty.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, ty.jstr);
+ }
+ }
+ (*env)->CallVoidMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, arr);
+ }
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ if (h->ver >= 0x020506 && cols[ncol]) {
+ mid = (*env)->GetMethodID(env, cls, "types",
+ "([Ljava/lang/String;)V");
+
+ if (mid) {
+ arr = (*env)->NewObjectArray(env, ncol,
+ C_java_lang_String, 0);
+ for (i = 0; i < ncol; i++) {
+ if (cols[i + ncol]) {
+ transstr ty;
+
+ trans2utf(env, h->haveutf, h->enc,
+ cols[i + ncol], &ty);
+ (*env)->SetObjectArrayElement(env, arr, i,
+ ty.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, ty.jstr);
+ }
+ }
+ (*env)->CallVoidMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, arr);
+ }
+ }
+#endif
+#if HAVE_SQLITE3
+ mid = (*env)->GetMethodID(env, cls, "types",
+ "([Ljava/lang/String;)V");
+
+ if (mid && h->stmt) {
+ arr = (*env)->NewObjectArray(env, ncol,
+ C_java_lang_String, 0);
+ for (i = 0; i < ncol; i++) {
+ const char *ctype = sqlite3_column_decltype(h->stmt, i);
+
+ if (!ctype) {
+ switch (sqlite3_column_type(h->stmt, i)) {
+ case SQLITE_INTEGER: ctype = "integer"; break;
+ case SQLITE_FLOAT: ctype = "double"; break;
+ default:
+#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT)
+ case SQLITE_TEXT:
+#else
+#ifdef SQLITE3_TEXT
+ case SQLITE3_TEXT:
+#endif
+#endif
+ ctype = "text"; break;
+ case SQLITE_BLOB: ctype = "blob"; break;
+ case SQLITE_NULL: ctype = "null"; break;
+ }
+ }
+ if (ctype) {
+ transstr ty;
+
+ trans2utf(env, 1, 0, ctype, &ty);
+ (*env)->SetObjectArrayElement(env, arr, i, ty.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, ty.jstr);
+ }
+ }
+ (*env)->CallVoidMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, arr);
+ }
+#endif
+#endif
+ }
+ mid = (*env)->GetMethodID(env, cls, "newrow",
+ "([Ljava/lang/String;)Z");
+ if (mid) {
+ jboolean rc;
+
+ if (data) {
+ arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0);
+ } else {
+ arr = 0;
+ }
+ for (i = 0; arr && i < ncol; i++) {
+ if (data[i]) {
+ transstr dats;
+
+ trans2utf(env, h->haveutf, h->enc, data[i], &dats);
+ (*env)->SetObjectArrayElement(env, arr, i, dats.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ (*env)->DeleteLocalRef(env, dats.jstr);
+ }
+ }
+ rc = (*env)->CallBooleanMethod(env, h->cb, mid, arr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return 1;
+ }
+ if (arr) {
+ (*env)->DeleteLocalRef(env, arr);
+ }
+ (*env)->DeleteLocalRef(env, cls);
+ return rc != JNI_FALSE;
+ }
+ }
+ return 0;
+}
+
+static void
+doclose(JNIEnv *env, jobject obj, int final)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h) {
+ hfunc *f;
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ hbl *bl;
+#endif
+#if HAVE_SQLITE_COMPILE
+ hvm *v;
+
+ while ((v = h->vms)) {
+ h->vms = v->next;
+ v->next = 0;
+ v->h = 0;
+ if (v->vm) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ } else {
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+#endif
+#endif
+ v->vm = 0;
+ }
+ }
+#endif
+ if (h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_close((sqlite3 *) h->sqlite);
+ } else {
+ sqlite_close((sqlite *) h->sqlite);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_close((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_close((sqlite3 *) h->sqlite);
+#endif
+#endif
+ h->sqlite = 0;
+ }
+ while ((f = h->funcs)) {
+ h->funcs = f->next;
+ f->h = 0;
+ f->sf = 0;
+ f->env = 0;
+ if (f->fc) {
+ (*env)->SetLongField(env, f->fc,
+ F_SQLite_FunctionContext_handle, 0);
+ }
+ delglobrefp(env, &f->db);
+ delglobrefp(env, &f->fi);
+ delglobrefp(env, &f->fc);
+ free(f);
+ }
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ while ((bl = h->blobs)) {
+ h->blobs = bl->next;
+ bl->next = 0;
+ bl->h = 0;
+ if (bl->blob) {
+ sqlite3_blob_close(bl->blob);
+ }
+ bl->blob = 0;
+ }
+#endif
+ delglobrefp(env, &h->bh);
+ delglobrefp(env, &h->cb);
+ delglobrefp(env, &h->ai);
+ delglobrefp(env, &h->tr);
+ delglobrefp(env, &h->ph);
+ delglobrefp(env, &h->enc);
+ free(h);
+ (*env)->SetLongField(env, obj, F_SQLite_Database_handle, 0);
+ return;
+ }
+ if (!final) {
+ throwclosed(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1close(JNIEnv *env, jobject obj)
+{
+ doclose(env, obj, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1finalize(JNIEnv *env, jobject obj)
+{
+ doclose(env, obj, 1);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1busy_1timeout(JNIEnv *env, jobject obj, jint ms)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms);
+ } else {
+ sqlite_busy_timeout((sqlite *) h->sqlite, ms);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_busy_timeout((sqlite *) h->sqlite, ms);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms);
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Database_version(JNIEnv *env, jclass cls)
+{
+ /* CHECK THIS */
+#if HAVE_BOTH_SQLITE
+ return (*env)->NewStringUTF(env, sqlite_libversion());
+#else
+#if HAVE_SQLITE2
+ return (*env)->NewStringUTF(env, sqlite_libversion());
+#else
+ return (*env)->NewStringUTF(env, sqlite3_libversion());
+#endif
+#endif
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Database_dbversion(JNIEnv *env, jobject obj)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ return (*env)->NewStringUTF(env, sqlite3_libversion());
+ } else {
+ return (*env)->NewStringUTF(env, sqlite_libversion());
+ }
+#else
+#if HAVE_SQLITE2
+ return (*env)->NewStringUTF(env, sqlite_libversion());
+#else
+ return (*env)->NewStringUTF(env, sqlite3_libversion());
+#endif
+#endif
+ }
+ return (*env)->NewStringUTF(env, "unknown");
+}
+
+JNIEXPORT jlong JNICALL
+Java_SQLite_Database__1last_1insert_1rowid(JNIEnv *env, jobject obj)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite);
+ } else {
+ return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite);
+ }
+#else
+#if HAVE_SQLITE2
+ return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite);
+#endif
+#endif
+ }
+ throwclosed(env);
+ return (jlong) 0;
+}
+
+JNIEXPORT jlong JNICALL
+Java_SQLite_Database__1changes(JNIEnv *env, jobject obj)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ return (jlong) sqlite3_changes((sqlite3 *) h->sqlite);
+ } else {
+ return (jlong) sqlite_changes((sqlite *) h->sqlite);
+ }
+#else
+#if HAVE_SQLITE2
+ return (jlong) sqlite_changes((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ return (jlong) sqlite3_changes((sqlite3 *) h->sqlite);
+#endif
+#endif
+ }
+ throwclosed(env);
+ return (jlong) 0;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Database__1complete(JNIEnv *env, jclass cls, jstring sql)
+{
+ transstr sqlstr;
+ jboolean result;
+
+ if (!sql) {
+ return JNI_FALSE;
+ }
+#if HAVE_BOTH_SQLITE || HAVE_SQLITE3
+ /* CHECK THIS */
+ trans2iso(env, 1, 0, sql, &sqlstr);
+ result = sqlite3_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE;
+#else
+ trans2iso(env, strcmp(sqlite_libencoding(), "UTF-8") == 0, 0,
+ sql, &sqlstr);
+ result = sqlite_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE;
+#endif
+ transfree(&sqlstr);
+ return result;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1interrupt(JNIEnv *env, jobject obj)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_interrupt((sqlite3 *) h->sqlite);
+ } else {
+ sqlite_interrupt((sqlite *) h->sqlite);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_interrupt((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_interrupt((sqlite3 *) h->sqlite);
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1open(JNIEnv *env, jobject obj, jstring file, jint mode)
+{
+ handle *h = gethandle(env, obj);
+ jthrowable exc;
+ char *err = 0;
+ transstr filename;
+ int maj, min, lev;
+
+ if (h) {
+ if (h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_close((sqlite3 *) h->sqlite);
+ } else {
+ sqlite_close((sqlite *) h->sqlite);
+ }
+ h->is3 = 0;
+#else
+#if HAVE_SQLITE2
+ sqlite_close((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_close((sqlite3 *) h->sqlite);
+#endif
+#endif
+ h->sqlite = 0;
+ }
+ } else {
+ h = malloc(sizeof (handle));
+ if (!h) {
+ throwoom(env, "unable to get SQLite handle");
+ return;
+ }
+ h->sqlite = 0;
+ h->bh = h->cb = h->ai = h->tr = h->ph = 0;
+ /* CHECK THIS */
+#if HAVE_BOTH_SQLITE
+ h->is3 = 0;
+ h->stmt = 0;
+ h->haveutf = 1;
+#else
+#if HAVE_SQLITE2
+ h->haveutf = strcmp(sqlite_libencoding(), "UTF-8") == 0;
+#endif
+#if HAVE_SQLITE3
+ h->stmt = 0;
+ h->haveutf = 1;
+#endif
+#endif
+ h->enc = 0;
+ h->funcs = 0;
+ h->ver = 0;
+#if HAVE_SQLITE_COMPILE
+ h->vms = 0;
+#endif
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ h->blobs = 0;
+#endif
+ }
+ h->env = 0;
+ if (!file) {
+ throwex(env, err ? err : "invalid file name");
+ return;
+ }
+ trans2iso(env, h->haveutf, h->enc, file, &filename);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+#if HAVE_BOTH_SQLITE
+ {
+ FILE *f = fopen(filename.result, "rb");
+ int c_0 = EOF;
+
+ if (f) {
+ c_0 = fgetc(f);
+ fclose(f);
+ }
+ if (c_0 != '*') {
+ int rc = sqlite3_open(filename.result, (sqlite3 **) &h->sqlite);
+
+ if (rc == SQLITE_OK) {
+ h->is3 = 1;
+ } else if (h->sqlite) {
+ sqlite3_close((sqlite3 *) h->sqlite);
+ h->sqlite = 0;
+ }
+ } else {
+ h->sqlite = (void *) sqlite_open(filename.result,
+ (int) mode, &err);
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ h->sqlite = (void *) sqlite_open(filename.result, (int) mode, &err);
+#endif
+#if HAVE_SQLITE3
+ if (sqlite3_open(filename.result, (sqlite3 **) &h->sqlite) != SQLITE_OK) {
+ if (h->sqlite) {
+ sqlite3_close((sqlite3 *) h->sqlite);
+ h->sqlite = 0;
+ }
+ }
+#endif
+#endif
+ transfree(&filename);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+ if (h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_close((sqlite3 *) h->sqlite);
+ h->is3 = 0;
+ } else {
+ sqlite_close((sqlite *) h->sqlite);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_close((sqlite *) h->sqlite);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_close((sqlite3 *) h->sqlite);
+#endif
+#endif
+ }
+ h->sqlite = 0;
+ return;
+ }
+ if (h->sqlite) {
+ jvalue v;
+
+ v.j = 0;
+ v.l = (jobject) h;
+ (*env)->SetLongField(env, obj, F_SQLite_Database_handle, v.j);
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev);
+ } else {
+ sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev);
+ }
+#else
+#if HAVE_SQLITE2
+ sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev);
+#endif
+#if HAVE_SQLITE3
+ sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev);
+#endif
+#endif
+ h->ver = ((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (lev & 0xFF);
+ return;
+ }
+ throwex(env, err ? err : "unknown error in open");
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1open_1aux_1file(JNIEnv *env, jobject obj, jstring file)
+{
+ handle *h = gethandle(env, obj);
+#if HAVE_SQLITE_OPEN_AUX_FILE
+ jboolean b;
+ jthrowable exc;
+ char *err = 0;
+ transstr filename;
+ int ret;
+#endif
+
+ if (h && h->sqlite) {
+#if HAVE_SQLITE_OPEN_AUX_FILE
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ throwex(env, "unsupported");
+ }
+#endif
+ trans2iso(env, h->haveutf, h->enc, file, &filename);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ ret = sqlite_open_aux_file((sqlite *) h->sqlite,
+ filename.result, &err);
+ transfree(&filename);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ if (err) {
+ sqlite_freemem(err);
+ }
+ return;
+ }
+ if (ret != SQLITE_OK) {
+ throwex(env, err ? err : sqlite_error_string(ret));
+ }
+ if (err) {
+ sqlite_freemem(err);
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1busy_1handler(JNIEnv *env, jobject obj, jobject bh)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+ delglobrefp(env, &h->bh);
+ globrefset(env, bh, &h->bh);
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h);
+ } else {
+ sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h);
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2
+ (JNIEnv *env, jobject obj, jstring sql, jobject cb)
+{
+ handle *h = gethandle(env, obj);
+ freemem *freeproc;
+
+ if (!sql) {
+ throwex(env, "invalid SQL statement");
+ return;
+ }
+ if (h) {
+ if (h->sqlite) {
+ jthrowable exc;
+ int rc;
+ char *err = 0;
+ transstr sqlstr;
+ jobject oldcb = globrefpop(env, &h->cb);
+
+ globrefset(env, cb, &h->cb);
+ h->env = env;
+ h->row1 = 1;
+ trans2iso(env, h->haveutf, h->enc, sql, &sqlstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result,
+ callback, h, &err);
+ freeproc = (freemem *) sqlite3_free;
+ } else {
+ rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result,
+ callback, h, &err);
+ freeproc = (freemem *) sqlite_freemem;
+ }
+#else
+#if HAVE_SQLITE2
+ rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result,
+ callback, h, &err);
+ freeproc = (freemem *) sqlite_freemem;
+#endif
+#if HAVE_SQLITE3
+ rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result,
+ callback, h, &err);
+ freeproc = (freemem *) sqlite3_free;
+#endif
+#endif
+ transfree(&sqlstr);
+ exc = (*env)->ExceptionOccurred(env);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ if (err) {
+ freeproc(err);
+ }
+ return;
+ }
+ if (rc != SQLITE_OK) {
+ char msg[128];
+
+ seterr(env, obj, rc);
+ if (!err) {
+ sprintf(msg, "error %d in sqlite*_exec", rc);
+ }
+ throwex(env, err ? err : msg);
+ }
+ if (err) {
+ freeproc(err);
+ }
+ return;
+ }
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2
+ (JNIEnv *env, jobject obj, jstring sql, jobject cb, jobjectArray args)
+{
+ handle *h = gethandle(env, obj);
+ freemem *freeproc = 0;
+
+ if (!sql) {
+ throwex(env, "invalid SQL statement");
+ return;
+ }
+ if (h) {
+ if (h->sqlite) {
+ jthrowable exc;
+ int rc = SQLITE_ERROR, nargs, i;
+ char *err = 0, *p;
+ const char *str = (*env)->GetStringUTFChars(env, sql, NULL);
+ transstr sqlstr;
+ struct args {
+ char *arg;
+ jobject obj;
+ transstr trans;
+ } *argv = 0;
+ char **cargv = 0;
+ jobject oldcb = globrefpop(env, &h->cb);
+
+ globrefset(env, cb, &h->cb);
+ p = (char *) str;
+ nargs = 0;
+ while (*p) {
+ if (*p == '%') {
+ ++p;
+ if (*p == 'q' || *p == 's') {
+ nargs++;
+ if (nargs > MAX_PARAMS) {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ throwex(env, "too much SQL parameters");
+ return;
+ }
+ } else if (h->ver >= 0x020500 && *p == 'Q') {
+ nargs++;
+ if (nargs > MAX_PARAMS) {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ throwex(env, "too much SQL parameters");
+ return;
+ }
+ } else if (*p != '%') {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ throwex(env, "bad % specification in query");
+ return;
+ }
+ }
+ ++p;
+ }
+ cargv = malloc((sizeof (*argv) + sizeof (char *))
+ * MAX_PARAMS);
+ if (!cargv) {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ throwoom(env, "unable to allocate arg vector");
+ return;
+ }
+ argv = (struct args *) (cargv + MAX_PARAMS);
+ for (i = 0; i < MAX_PARAMS; i++) {
+ cargv[i] = 0;
+ argv[i].arg = 0;
+ argv[i].obj = 0;
+ argv[i].trans.result = argv[i].trans.tofree = 0;
+ }
+ exc = 0;
+ for (i = 0; i < nargs; i++) {
+ jobject so = (*env)->GetObjectArrayElement(env, args, i);
+
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ break;
+ }
+ if (so) {
+ argv[i].obj = so;
+ argv[i].arg = cargv[i] =
+ trans2iso(env, h->haveutf, h->enc, argv[i].obj,
+ &argv[i].trans);
+ }
+ }
+ if (exc) {
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ freep((char **) &cargv);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ return;
+ }
+ h->env = env;
+ h->row1 = 1;
+ trans2iso(env, h->haveutf, h->enc, sql, &sqlstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (!exc) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+ char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv);
+#else
+ char *s = sqlite3_mprintf(sqlstr.result,
+ cargv[0], cargv[1],
+ cargv[2], cargv[3],
+ cargv[4], cargv[5],
+ cargv[6], cargv[7],
+ cargv[8], cargv[9],
+ cargv[10], cargv[11],
+ cargv[12], cargv[13],
+ cargv[14], cargv[15],
+ cargv[16], cargv[17],
+ cargv[18], cargv[19],
+ cargv[20], cargv[21],
+ cargv[22], cargv[23],
+ cargv[24], cargv[25],
+ cargv[26], cargv[27],
+ cargv[28], cargv[29],
+ cargv[30], cargv[31]);
+#endif
+
+ if (s) {
+ rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback,
+ h, &err);
+ sqlite3_free(s);
+ } else {
+ rc = SQLITE_NOMEM;
+ }
+ freeproc = (freemem *) sqlite3_free;
+ } else {
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+ rc = sqlite_exec_vprintf((sqlite *) h->sqlite,
+ sqlstr.result, callback, h, &err,
+ (char *) cargv);
+#else
+ rc = sqlite_exec_printf((sqlite *) h->sqlite,
+ sqlstr.result, callback,
+ h, &err,
+ cargv[0], cargv[1],
+ cargv[2], cargv[3],
+ cargv[4], cargv[5],
+ cargv[6], cargv[7],
+ cargv[8], cargv[9],
+ cargv[10], cargv[11],
+ cargv[12], cargv[13],
+ cargv[14], cargv[15],
+ cargv[16], cargv[17],
+ cargv[18], cargv[19],
+ cargv[20], cargv[21],
+ cargv[22], cargv[23],
+ cargv[24], cargv[25],
+ cargv[26], cargv[27],
+ cargv[28], cargv[29],
+ cargv[30], cargv[31]);
+#endif
+ freeproc = (freemem *) sqlite_freemem;
+ }
+#else
+#if HAVE_SQLITE2
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+ rc = sqlite_exec_vprintf((sqlite *) h->sqlite, sqlstr.result,
+ callback, h, &err, (char *) cargv);
+#else
+ rc = sqlite_exec_printf((sqlite *) h->sqlite, sqlstr.result,
+ callback, h, &err,
+ cargv[0], cargv[1],
+ cargv[2], cargv[3],
+ cargv[4], cargv[5],
+ cargv[6], cargv[7],
+ cargv[8], cargv[9],
+ cargv[10], cargv[11],
+ cargv[12], cargv[13],
+ cargv[14], cargv[15],
+ cargv[16], cargv[17],
+ cargv[18], cargv[19],
+ cargv[20], cargv[21],
+ cargv[22], cargv[23],
+ cargv[24], cargv[25],
+ cargv[26], cargv[27],
+ cargv[28], cargv[29],
+ cargv[30], cargv[31]);
+#endif
+ freeproc = (freemem *) sqlite_freemem;
+#endif
+#if HAVE_SQLITE3
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+ char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv);
+#else
+ char *s = sqlite3_mprintf(sqlstr.result,
+ cargv[0], cargv[1],
+ cargv[2], cargv[3],
+ cargv[4], cargv[5],
+ cargv[6], cargv[7],
+ cargv[8], cargv[9],
+ cargv[10], cargv[11],
+ cargv[12], cargv[13],
+ cargv[14], cargv[15],
+ cargv[16], cargv[17],
+ cargv[18], cargv[19],
+ cargv[20], cargv[21],
+ cargv[22], cargv[23],
+ cargv[24], cargv[25],
+ cargv[26], cargv[27],
+ cargv[28], cargv[29],
+ cargv[30], cargv[31]);
+#endif
+
+ if (s) {
+ rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback,
+ h, &err);
+ sqlite3_free(s);
+ } else {
+ rc = SQLITE_NOMEM;
+ }
+ freeproc = (freemem *) sqlite3_free;
+#endif
+#endif
+ exc = (*env)->ExceptionOccurred(env);
+ }
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ transfree(&sqlstr);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ freep((char **) &cargv);
+ delglobrefp(env, &h->cb);
+ h->cb = oldcb;
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ if (err && freeproc) {
+ freeproc(err);
+ }
+ return;
+ }
+ if (rc != SQLITE_OK) {
+ char msg[128];
+
+ seterr(env, obj, rc);
+ if (!err) {
+ sprintf(msg, "error %d in sqlite*_exec", rc);
+ }
+ throwex(env, err ? err : msg);
+ }
+ if (err && freeproc) {
+ freeproc(err);
+ }
+ return;
+ }
+ }
+ throwclosed(env);
+}
+
+static hfunc *
+getfunc(JNIEnv *env, jobject obj)
+{
+ jvalue v;
+
+ v.j = (*env)->GetLongField(env, obj, F_SQLite_FunctionContext_handle);
+ return (hfunc *) v.l;
+}
+
+#if HAVE_SQLITE2
+static void
+call_common(sqlite_func *sf, int isstep, int nargs, const char **args)
+{
+ hfunc *f = (hfunc *) sqlite_user_data(sf);
+
+ if (f && f->env && f->fi) {
+ JNIEnv *env = f->env;
+ jclass cls = (*env)->GetObjectClass(env, f->fi);
+ jmethodID mid =
+ (*env)->GetMethodID(env, cls,
+ isstep ? "step" : "function",
+ "(LSQLite/FunctionContext;[Ljava/lang/String;)V");
+ jobjectArray arr;
+ int i;
+
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return;
+ }
+ arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0);
+ for (i = 0; i < nargs; i++) {
+ if (args[i]) {
+ transstr arg;
+ jthrowable exc;
+
+ trans2utf(env, f->h->haveutf, f->h->enc, args[i], &arg);
+ (*env)->SetObjectArrayElement(env, arr, i, arg.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ (*env)->DeleteLocalRef(env, arg.jstr);
+ }
+ }
+ f->sf = sf;
+ (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr);
+ (*env)->DeleteLocalRef(env, arr);
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+
+static void
+call_func(sqlite_func *sf, int nargs, const char **args)
+{
+ call_common(sf, 0, nargs, args);
+}
+
+static void
+call_step(sqlite_func *sf, int nargs, const char **args)
+{
+ call_common(sf, 1, nargs, args);
+}
+
+static void
+call_final(sqlite_func *sf)
+{
+ hfunc *f = (hfunc *) sqlite_user_data(sf);
+
+ if (f && f->env && f->fi) {
+ JNIEnv *env = f->env;
+ jclass cls = (*env)->GetObjectClass(env, f->fi);
+ jmethodID mid = (*env)->GetMethodID(env, cls, "last_step",
+ "(LSQLite/FunctionContext;)V");
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return;
+ }
+ f->sf = sf;
+ (*env)->CallVoidMethod(env, f->fi, mid, f->fc);
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+#endif
+
+#if HAVE_SQLITE3
+static void
+call3_common(sqlite3_context *sf, int isstep, int nargs, sqlite3_value **args)
+{
+ hfunc *f = (hfunc *) sqlite3_user_data(sf);
+
+ if (f && f->env && f->fi) {
+ JNIEnv *env = f->env;
+ jclass cls = (*env)->GetObjectClass(env, f->fi);
+ jmethodID mid =
+ (*env)->GetMethodID(env, cls,
+ isstep ? "step" : "function",
+ "(LSQLite/FunctionContext;[Ljava/lang/String;)V");
+ jobjectArray arr;
+ int i;
+
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return;
+ }
+ arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0);
+ for (i = 0; i < nargs; i++) {
+ if (args[i]) {
+ transstr arg;
+ jthrowable exc;
+
+ trans2utf(env, 1, 0, (char *) sqlite3_value_text(args[i]),
+ &arg);
+ (*env)->SetObjectArrayElement(env, arr, i, arg.jstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ (*env)->DeleteLocalRef(env, arg.jstr);
+ }
+ }
+ f->sf = sf;
+ (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr);
+ (*env)->DeleteLocalRef(env, arr);
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+
+static void
+call3_func(sqlite3_context *sf, int nargs, sqlite3_value **args)
+{
+ call3_common(sf, 0, nargs, args);
+}
+
+static void
+call3_step(sqlite3_context *sf, int nargs, sqlite3_value **args)
+{
+ call3_common(sf, 1, nargs, args);
+}
+
+static void
+call3_final(sqlite3_context *sf)
+{
+ hfunc *f = (hfunc *) sqlite3_user_data(sf);
+
+ if (f && f->env && f->fi) {
+ JNIEnv *env = f->env;
+ jclass cls = (*env)->GetObjectClass(env, f->fi);
+ jmethodID mid = (*env)->GetMethodID(env, cls, "last_step",
+ "(LSQLite/FunctionContext;)V");
+ if (mid == 0) {
+ (*env)->DeleteLocalRef(env, cls);
+ return;
+ }
+ f->sf = sf;
+ (*env)->CallVoidMethod(env, f->fi, mid, f->fc);
+ (*env)->DeleteLocalRef(env, cls);
+ }
+}
+#endif
+
+static void
+mkfunc_common(JNIEnv *env, int isagg, jobject obj, jstring name,
+ jint nargs, jobject fi)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+ jclass cls = (*env)->FindClass(env, "SQLite/FunctionContext");
+ jobject fc;
+ hfunc *f;
+ int ret;
+ transstr namestr;
+ jvalue v;
+ jthrowable exc;
+
+ fc = (*env)->AllocObject(env, cls);
+ if (!fi) {
+ throwex(env, "null SQLite.Function not allowed");
+ return;
+ }
+ f = malloc(sizeof (hfunc));
+ if (!f) {
+ throwoom(env, "unable to get SQLite.FunctionContext handle");
+ return;
+ }
+ globrefset(env, fc, &f->fc);
+ globrefset(env, fi, &f->fi);
+ globrefset(env, obj, &f->db);
+ f->h = h;
+ f->next = h->funcs;
+ h->funcs = f;
+ f->sf = 0;
+ f->env = env;
+ v.j = 0;
+ v.l = (jobject) f;
+ (*env)->SetLongField(env, f->fc, F_SQLite_FunctionContext_handle, v.j);
+ trans2iso(env, h->haveutf, h->enc, name, &namestr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+#if HAVE_BOTH_SQLITE
+ f->is3 = h->is3;
+ if (h->is3) {
+ ret = sqlite3_create_function((sqlite3 *) h->sqlite,
+ namestr.result,
+ (int) nargs,
+ SQLITE_UTF8, f,
+ isagg ? NULL : call3_func,
+ isagg ? call3_step : NULL,
+ isagg ? call3_final : NULL);
+
+ } else {
+ if (isagg) {
+ ret = sqlite_create_aggregate((sqlite *) h->sqlite,
+ namestr.result,
+ (int) nargs,
+ call_step, call_final, f);
+ } else {
+ ret = sqlite_create_function((sqlite *) h->sqlite,
+ namestr.result,
+ (int) nargs,
+ call_func, f);
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ if (isagg) {
+ ret = sqlite_create_aggregate((sqlite *) h->sqlite, namestr.result,
+ (int) nargs,
+ call_step, call_final, f);
+ } else {
+ ret = sqlite_create_function((sqlite *) h->sqlite, namestr.result,
+ (int) nargs,
+ call_func, f);
+ }
+#endif
+#if HAVE_SQLITE3
+ ret = sqlite3_create_function((sqlite3 *) h->sqlite,
+ namestr.result,
+ (int) nargs,
+ SQLITE_UTF8, f,
+ isagg ? NULL : call3_func,
+ isagg ? call3_step : NULL,
+ isagg ? call3_final : NULL);
+#endif
+#endif
+ transfree(&namestr);
+ if (ret != SQLITE_OK) {
+ throwex(env, "error creating function/aggregate");
+ }
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1create_1aggregate(JNIEnv *env, jobject obj,
+ jstring name, jint nargs, jobject fi)
+{
+ mkfunc_common(env, 1, obj, name, nargs, fi);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1create_1function(JNIEnv *env, jobject obj,
+ jstring name, jint nargs, jobject fi)
+{
+ mkfunc_common(env, 0, obj, name, nargs, fi);
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1function_1type(JNIEnv *env, jobject obj,
+ jstring name, jint type)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ return;
+ }
+#endif
+#if HAVE_SQLITE2
+#if HAVE_SQLITE_FUNCTION_TYPE
+ {
+ int ret;
+ transstr namestr;
+ jthrowable exc;
+
+ trans2iso(env, h->haveutf, h->enc, name, &namestr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ ret = sqlite_function_type(h->sqlite, namestr.result, (int) type);
+ transfree(&namestr);
+ if (ret != SQLITE_OK) {
+ throwex(env, sqlite_error_string(ret));
+ }
+ }
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_FunctionContext_count(JNIEnv *env, jobject obj)
+{
+ hfunc *f = getfunc(env, obj);
+ jint r = 0;
+
+ if (f && f->sf) {
+#if HAVE_SQLITE_BOTH
+ if (f->is3) {
+ r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf);
+ } else {
+ r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf);
+ }
+#else
+#if HAVE_SQLITE2
+ r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf);
+#endif
+#if HAVE_SQLITE3
+ r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf);
+#endif
+#endif
+ }
+ return r;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1error(JNIEnv *env, jobject obj, jstring err)
+{
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (!f->is3) {
+ transstr errstr;
+ jthrowable exc;
+
+ trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ sqlite_set_result_error((sqlite_func *) f->sf,
+ errstr.result, -1);
+ transfree(&errstr);
+ } else if (err) {
+ jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar);
+ const jchar *str = (*env)->GetStringChars(env, err, 0);
+
+ sqlite3_result_error16((sqlite3_context *) f->sf, str, len);
+ (*env)->ReleaseStringChars(env, err, str);
+ } else {
+ sqlite3_result_error((sqlite3_context *) f->sf,
+ "null error text", -1);
+ }
+#else
+#if HAVE_SQLITE2
+ transstr errstr;
+ jthrowable exc;
+
+ trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ sqlite_set_result_error((sqlite_func *) f->sf, errstr.result, -1);
+ transfree(&errstr);
+#endif
+#if HAVE_SQLITE3
+ if (err) {
+ jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar);
+ const jchar *str = (*env)->GetStringChars(env, err, 0);
+
+ sqlite3_result_error16((sqlite3_context *) f->sf, str, len);
+ (*env)->ReleaseStringChars(env, err, str);
+ } else {
+ sqlite3_result_error((sqlite3_context *) f->sf,
+ "null error text", -1);
+ }
+#endif
+#endif
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1result__D(JNIEnv *env, jobject obj, jdouble d)
+{
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (f->is3) {
+ sqlite3_result_double((sqlite3_context *) f->sf, (double) d);
+ } else {
+ sqlite_set_result_double((sqlite_func *) f->sf, (double) d);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_set_result_double((sqlite_func *) f->sf, (double) d);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_result_double((sqlite3_context *) f->sf, (double) d);
+#endif
+#endif
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1result__I(JNIEnv *env, jobject obj, jint i)
+{
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (f->is3) {
+ sqlite3_result_int((sqlite3_context *) f->sf, (int) i);
+ } else {
+ sqlite_set_result_int((sqlite_func *) f->sf, (int) i);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_set_result_int((sqlite_func *) f->sf, (int) i);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_result_int((sqlite3_context *) f->sf, (int) i);
+#endif
+#endif
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2(JNIEnv *env,
+ jobject obj,
+ jstring ret)
+{
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (!f->is3) {
+ transstr retstr;
+ jthrowable exc;
+
+ trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ sqlite_set_result_string((sqlite_func *) f->sf,
+ retstr.result, -1);
+ transfree(&retstr);
+ } else if (ret) {
+ jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar);
+ const jchar *str = (*env)->GetStringChars(env, ret, 0);
+
+ sqlite3_result_text16((sqlite3_context *) f->sf, str, len,
+ SQLITE_TRANSIENT);
+ (*env)->ReleaseStringChars(env, ret, str);
+ } else {
+ sqlite3_result_null((sqlite3_context *) f->sf);
+ }
+#else
+#if HAVE_SQLITE2
+ transstr retstr;
+ jthrowable exc;
+
+ trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ sqlite_set_result_string((sqlite_func *) f->sf, retstr.result, -1);
+ transfree(&retstr);
+#endif
+#if HAVE_SQLITE3
+ if (ret) {
+ jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar);
+ const jchar *str = (*env)->GetStringChars(env, ret, 0);
+
+ sqlite3_result_text16((sqlite3_context *) f->sf, str, len,
+ SQLITE_TRANSIENT);
+ (*env)->ReleaseStringChars(env, ret, str);
+ } else {
+ sqlite3_result_null((sqlite3_context *) f->sf);
+ }
+#endif
+#endif
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1result___3B(JNIEnv *env, jobject obj,
+ jbyteArray b)
+{
+#if HAVE_SQLITE3
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (!f->is3) {
+ /* silently ignored */
+ return;
+ }
+#endif
+ if (b) {
+ jsize len;
+ jbyte *data;
+
+ len = (*env)->GetArrayLength(env, b);
+ data = (*env)->GetByteArrayElements(env, b, 0);
+ sqlite3_result_blob((sqlite3_context *) f->sf,
+ data, len, SQLITE_TRANSIENT);
+ (*env)->ReleaseByteArrayElements(env, b, data, 0);
+ } else {
+ sqlite3_result_null((sqlite3_context *) f->sf);
+ }
+ }
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_set_1result_1zeroblob(JNIEnv *env, jobject obj,
+ jint n)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_RESULT_ZEROBLOB
+ hfunc *f = getfunc(env, obj);
+
+ if (f && f->sf) {
+#if HAVE_BOTH_SQLITE
+ if (!f->is3) {
+ /* silently ignored */
+ return;
+ }
+#endif
+ sqlite3_result_zeroblob((sqlite3_context *) f->sf, n);
+ }
+#endif
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Database_error_1string(JNIEnv *env, jclass c, jint err)
+{
+#if HAVE_SQLITE2
+ return (*env)->NewStringUTF(env, sqlite_error_string((int) err));
+#else
+ return (*env)->NewStringUTF(env, "unkown error");
+#endif
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Database__1errmsg(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+#if HAVE_BOTH_SQLITE
+ if (!h->is3) {
+ return 0;
+ }
+#endif
+ return (*env)->NewStringUTF(env,
+ sqlite3_errmsg((sqlite3 *) h->sqlite));
+ }
+#endif
+ return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1set_1encoding(JNIEnv *env, jobject obj, jstring enc)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && !h->haveutf) {
+#if HAVE_BOTH_SQLITE
+ if (!h->is3) {
+ delglobrefp(env, &h->enc);
+ h->enc = enc;
+ globrefset(env, enc, &h->enc);
+ }
+#else
+#if HAVE_SQLITE2
+ delglobrefp(env, &h->enc);
+ h->enc = enc;
+ globrefset(env, enc, &h->enc);
+#endif
+#endif
+ }
+}
+
+#if HAVE_SQLITE_SET_AUTHORIZER
+static int
+doauth(void *arg, int what, const char *arg1, const char *arg2,
+ const char *arg3, const char *arg4)
+{
+ handle *h = (handle *) arg;
+ JNIEnv *env = h->env;
+
+ if (env && h->ai) {
+ jthrowable exc;
+ jclass cls = (*env)->GetObjectClass(env, h->ai);
+ jmethodID mid;
+ jint i = what;
+
+ mid = (*env)->GetMethodID(env, cls, "authorize",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I");
+ if (mid) {
+ jstring s1 = 0, s2 = 0, s3 = 0, s4 = 0;
+ transstr tr;
+
+ if (arg1) {
+ trans2utf(env, h->haveutf, h->enc, arg1, &tr);
+ s1 = tr.jstr;
+ }
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return SQLITE_DENY;
+ }
+ if (arg2) {
+ trans2utf(env, h->haveutf, h->enc, arg2, &tr);
+ s2 = tr.jstr;
+ }
+ if (arg3) {
+ trans2utf(env, h->haveutf, h->enc, arg3, &tr);
+ s3 = tr.jstr;
+ }
+ if (arg4) {
+ trans2utf(env, h->haveutf, h->enc, arg4, &tr);
+ s4 = tr.jstr;
+ }
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return SQLITE_DENY;
+ }
+ i = (*env)->CallIntMethod(env, h->ai, mid, i, s1, s2, s3, s4);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return SQLITE_DENY;
+ }
+ (*env)->DeleteLocalRef(env, s4);
+ (*env)->DeleteLocalRef(env, s3);
+ (*env)->DeleteLocalRef(env, s2);
+ (*env)->DeleteLocalRef(env, s1);
+ if (i != SQLITE_OK && i != SQLITE_IGNORE) {
+ i = SQLITE_DENY;
+ }
+ return (int) i;
+ }
+ }
+ return SQLITE_DENY;
+}
+#endif
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1set_1authorizer(JNIEnv *env, jobject obj, jobject auth)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+ delglobrefp(env, &h->ai);
+ globrefset(env, auth, &h->ai);
+#if HAVE_SQLITE_SET_AUTHORIZER
+ h->env = env;
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_set_authorizer((sqlite3 *) h->sqlite,
+ h->ai ? doauth : 0, h);
+ } else {
+ sqlite_set_authorizer((sqlite *) h->sqlite,
+ h->ai ? doauth : 0, h);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_set_authorizer((sqlite *) h->sqlite, h->ai ? doauth : 0, h);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_set_authorizer((sqlite3 *) h->sqlite, h->ai ? doauth : 0, h);
+#endif
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+#if HAVE_SQLITE_TRACE
+static void
+dotrace(void *arg, const char *msg)
+{
+ handle *h = (handle *) arg;
+ JNIEnv *env = h->env;
+
+ if (env && h->tr && msg) {
+ jthrowable exc;
+ jclass cls = (*env)->GetObjectClass(env, h->tr);
+ jmethodID mid;
+
+ mid = (*env)->GetMethodID(env, cls, "trace", "(Ljava/lang/String;)V");
+ if (mid) {
+ transstr tr;
+
+ trans2utf(env, h->haveutf, h->enc, msg, &tr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ (*env)->ExceptionClear(env);
+ return;
+ }
+ (*env)->CallVoidMethod(env, h->tr, mid, tr.jstr);
+ (*env)->ExceptionClear(env);
+ (*env)->DeleteLocalRef(env, tr.jstr);
+ return;
+ }
+ }
+ return;
+}
+#endif
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1trace(JNIEnv *env, jobject obj, jobject tr)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+ delglobrefp(env, &h->tr);
+ globrefset(env, tr, &h->tr);
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h);
+ } else {
+#if HAVE_SQLITE_TRACE
+ sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h);
+#endif
+ }
+#else
+#if HAVE_SQLITE2
+#if HAVE_SQLITE_TRACE
+ sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h);
+#endif
+#endif
+#if HAVE_SQLITE3
+ sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h);
+#endif
+#endif
+ return;
+ }
+ throwclosed(env);
+}
+
+#if HAVE_SQLITE_COMPILE
+static void
+dovmfinal(JNIEnv *env, jobject obj, int final)
+{
+ hvm *v = gethvm(env, obj);
+
+ if (v) {
+ if (v->h) {
+ handle *h = v->h;
+ hvm *vv, **vvp;
+
+ vvp = &h->vms;
+ vv = *vvp;
+ while (vv) {
+ if (vv == v) {
+ *vvp = vv->next;
+ break;
+ }
+ vvp = &vv->next;
+ vv = *vvp;
+ }
+ }
+ if (v->vm) {
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ } else {
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+#endif
+#endif
+ v->vm = 0;
+ }
+ free(v);
+ (*env)->SetLongField(env, obj, F_SQLite_Vm_handle, 0);
+ return;
+ }
+ if (!final) {
+ throwex(env, "vm already closed");
+ }
+}
+#endif
+
+#if HAVE_SQLITE3
+static void
+dostmtfinal(JNIEnv *env, jobject obj)
+{
+ hvm *v = gethstmt(env, obj);
+
+ if (v) {
+ if (v->h) {
+ handle *h = v->h;
+ hvm *vv, **vvp;
+
+ vvp = &h->vms;
+ vv = *vvp;
+ while (vv) {
+ if (vv == v) {
+ *vvp = vv->next;
+ break;
+ }
+ vvp = &vv->next;
+ vv = *vvp;
+ }
+ }
+ if (v->vm) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ }
+ v->vm = 0;
+ free(v);
+ (*env)->SetLongField(env, obj, F_SQLite_Stmt_handle, 0);
+ }
+}
+#endif
+
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+static void
+doblobfinal(JNIEnv *env, jobject obj)
+{
+ hbl *bl = gethbl(env, obj);
+
+ if (bl) {
+ if (bl->h) {
+ handle *h = bl->h;
+ hbl *blc, **blp;
+
+ blp = &h->blobs;
+ blc = *blp;
+ while (blc) {
+ if (blc == bl) {
+ *blp = blc->next;
+ break;
+ }
+ blp = &blc->next;
+ blc = *blp;
+ }
+ }
+ if (bl->blob) {
+ sqlite3_blob_close(bl->blob);
+ }
+ bl->blob = 0;
+ free(bl);
+ (*env)->SetLongField(env, obj, F_SQLite_Blob_handle, 0);
+ (*env)->SetIntField(env, obj, F_SQLite_Blob_size, 0);
+ }
+}
+#endif
+
+JNIEXPORT void JNICALL
+Java_SQLite_Vm_stop(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE_COMPILE
+ dovmfinal(env, obj, 0);
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Vm_finalize(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE_COMPILE
+ dovmfinal(env, obj, 1);
+#endif
+}
+
+#if HAVE_SQLITE_COMPILE
+#if HAVE_SQLITE3
+static void
+free_tab(void *mem)
+{
+ char **p = (char **) mem;
+ int i, n;
+
+ if (!p) {
+ return;
+ }
+ p -= 1;
+ mem = (void *) p;
+ n = ((int *) p)[0];
+ p += n * 2 + 2 + 1;
+ for (i = 0; i < n; i++) {
+ if (p[i]) {
+ free(p[i]);
+ }
+ }
+ free(mem);
+}
+#endif
+#endif
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Vm_step(JNIEnv *env, jobject obj, jobject cb)
+{
+#if HAVE_SQLITE_COMPILE
+ hvm *v = gethvm(env, obj);
+
+ if (v && v->vm && v->h) {
+ jthrowable exc;
+ int ret, ncol = 0;
+#if HAVE_SQLITE3
+ freemem *freeproc = 0;
+ const char **blob = 0;
+#endif
+ const char **data = 0, **cols = 0;
+
+ v->h->env = env;
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ ret = sqlite3_step((sqlite3_stmt *) v->vm);
+ if (ret == SQLITE_ROW) {
+ ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+ if (ncol > 0) {
+ data = calloc(ncol * 3 + 3 + 1, sizeof (char *));
+ if (data) {
+ data[0] = (const char *) ncol;
+ ++data;
+ cols = data + ncol + 1;
+ blob = cols + ncol + 1;
+ freeproc = free_tab;
+ } else {
+ ret = SQLITE_NOMEM;
+ }
+ }
+ if (ret != SQLITE_NOMEM) {
+ int i;
+
+ for (i = 0; i < ncol; i++) {
+ cols[i] =
+ sqlite3_column_name((sqlite3_stmt *) v->vm, i);
+ if (sqlite3_column_type((sqlite3_stmt *) v->vm, i)
+ == SQLITE_BLOB) {
+ unsigned char *src = (unsigned char *)
+ sqlite3_column_blob((sqlite3_stmt *) v->vm, i);
+ int n =
+ sqlite3_column_bytes((sqlite3_stmt *) v->vm,
+ i);
+
+ if (src) {
+ data[i] = malloc(n * 2 + 4);
+ if (data[i]) {
+ int k;
+ char *p = (char *) data[i];
+
+ blob[i] = data[i];
+ *p++ = 'X';
+ *p++ = '\'';
+ for (k = 0; k < n; k++) {
+ *p++ = xdigits[src[k] >> 4];
+ *p++ = xdigits[src[k] & 0x0F];
+ }
+ *p++ = '\'';
+ *p++ = '\0';
+ }
+ }
+ } else {
+ data[i] = (const char *)
+ sqlite3_column_text((sqlite3_stmt *) v->vm, i);
+ }
+ }
+ }
+ }
+ } else {
+ ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols);
+ }
+#else
+#if HAVE_SQLITE2
+ ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols);
+#endif
+#if HAVE_SQLITE3
+ ret = sqlite3_step((sqlite3_stmt *) v->vm);
+ if (ret == SQLITE_ROW) {
+ ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+ if (ncol > 0) {
+ data = calloc(ncol * 3 + 3 + 1, sizeof (char *));
+ if (data) {
+ data[0] = (const char *) ncol;
+ ++data;
+ cols = data + ncol + 1;
+ blob = cols + ncol + 1;
+ freeproc = free_tab;
+ } else {
+ ret = SQLITE_NOMEM;
+ }
+ }
+ if (ret != SQLITE_NOMEM) {
+ int i;
+
+ for (i = 0; i < ncol; i++) {
+ cols[i] = sqlite3_column_name((sqlite3_stmt *) v->vm, i);
+ if (sqlite3_column_type((sqlite3_stmt *) v->vm, i)
+ == SQLITE_BLOB) {
+ unsigned char *src = (unsigned char *)
+ sqlite3_column_blob((sqlite3_stmt *) v->vm, i);
+ int n =
+ sqlite3_column_bytes((sqlite3_stmt *) v->vm, i);
+
+ if (src) {
+ data[i] = malloc(n * 2 + 4);
+ if (data[i]) {
+ int k;
+ char *p = (char *) data[i];
+
+ blob[i] = data[i];
+ *p++ = 'X';
+ *p++ = '\'';
+ for (k = 0; k < n; k++) {
+ *p++ = xdigits[src[k] >> 4];
+ *p++ = xdigits[src[k] & 0x0F];
+ }
+ *p++ = '\'';
+ *p++ = '\0';
+ }
+ }
+ } else {
+ data[i] = (char *)
+ sqlite3_column_text((sqlite3_stmt *) v->vm, i);
+ }
+ }
+ }
+ }
+#endif
+#endif
+ if (ret == SQLITE_ROW) {
+ v->hh.cb = cb;
+ v->hh.env = env;
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ v->hh.stmt = (sqlite3_stmt *) v->vm;
+ }
+#else
+#if HAVE_SQLITE3
+ v->hh.stmt = (sqlite3_stmt *) v->vm;
+#endif
+#endif
+ callback((void *) &v->hh, ncol, (char **) data, (char **) cols);
+#if HAVE_SQLITE3
+ if (data && freeproc) {
+ freeproc((void *) data);
+ }
+#endif
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ goto dofin;
+ }
+ return JNI_TRUE;
+ } else if (ret == SQLITE_DONE) {
+dofin:
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ } else {
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+#endif
+#endif
+ v->vm = 0;
+ return JNI_FALSE;
+ }
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ } else {
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+#endif
+#endif
+ setvmerr(env, obj, ret);
+ v->vm = 0;
+ throwex(env, "error in step");
+ return JNI_FALSE;
+ }
+ throwex(env, "vm already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Vm_compile(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE_COMPILE
+ hvm *v = gethvm(env, obj);
+ void *svm = 0;
+ char *err = 0;
+ const char *tail;
+ int ret;
+
+ if (v && v->vm) {
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ } else {
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) v->vm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+#endif
+#endif
+ v->vm = 0;
+ }
+ if (v && v->h && v->h->sqlite) {
+ if (!v->tail) {
+ return JNI_FALSE;
+ }
+ v->h->env = env;
+#if HAVE_BOTH_SQLITE
+ if (v->is3) {
+#if HAVE_SQLITE3_PREPARE_V2
+ ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite, v->tail, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#else
+ ret = sqlite3_prepare((sqlite3 *) v->h->sqlite, v->tail, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+ } else {
+ ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail,
+ &tail, (sqlite_vm **) &svm, &err);
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite_finalize((sqlite_vm *) svm, 0);
+ svm = 0;
+ }
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail,
+ &tail, (sqlite_vm **) &svm, &err);
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite_finalize((sqlite_vm *) svm, 0);
+ svm = 0;
+ }
+ }
+#endif
+#if HAVE_SQLITE3
+#if HAVE_SQLITE3_PREPARE_V2
+ ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite,
+ v->tail, -1, (sqlite3_stmt **) &svm, &tail);
+#else
+ ret = sqlite3_prepare((sqlite3 *) v->h->sqlite,
+ v->tail, -1, (sqlite3_stmt **) &svm, &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+#endif
+#endif
+ if (ret != SQLITE_OK) {
+ setvmerr(env, obj, ret);
+ v->tail = 0;
+ throwex(env, err ? err : "error in compile/prepare");
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+ return JNI_FALSE;
+ }
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+ if (!svm) {
+ v->tail = 0;
+ return JNI_FALSE;
+ }
+ v->vm = svm;
+ v->tail = (char *) tail;
+ v->hh.row1 = 1;
+ return JNI_TRUE;
+ }
+ throwex(env, "vm already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database_vm_1compile(JNIEnv *env, jobject obj, jstring sql,
+ jobject vm)
+{
+#if HAVE_SQLITE_COMPILE
+ handle *h = gethandle(env, obj);
+ void *svm = 0;
+ hvm *v;
+ char *err = 0;
+ const char *tail;
+ transstr tr;
+ jvalue vv;
+ int ret;
+ jthrowable exc;
+
+ if (!h) {
+ throwclosed(env);
+ return;
+ }
+ if (!vm) {
+ throwex(env, "null vm");
+ return;
+ }
+ if (!sql) {
+ throwex(env, "null sql");
+ return;
+ }
+ trans2iso(env, h->haveutf, h->enc, sql, &tr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ h->env = env;
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+#if HAVE_SQLITE3_PREPARE_V2
+ ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#else
+ ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+ } else {
+ ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail,
+ (sqlite_vm **) &svm, &err);
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite_finalize((sqlite_vm *) svm, 0);
+ }
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail,
+ (sqlite_vm **) &svm, &err);
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite_finalize((sqlite_vm *) svm, 0);
+ svm = 0;
+ }
+ }
+#endif
+#if HAVE_SQLITE3
+#if HAVE_SQLITE3_PREPARE_V2
+ ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#else
+ ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+#endif
+#endif
+ if (ret != SQLITE_OK) {
+ transfree(&tr);
+ setvmerr(env, vm, ret);
+ throwex(env, err ? err : "error in prepare/compile");
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+ return;
+ }
+#if HAVE_SQLITE2
+ if (err) {
+ sqlite_freemem(err);
+ }
+#endif
+ if (!svm) {
+ transfree(&tr);
+ return;
+ }
+ v = malloc(sizeof (hvm) + strlen(tail) + 1);
+ if (!v) {
+ transfree(&tr);
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ } else {
+ sqlite_finalize((sqlite_vm *) svm, 0);
+ }
+#else
+#if HAVE_SQLITE2
+ sqlite_finalize((sqlite_vm *) svm, 0);
+#endif
+#if HAVE_SQLITE3
+ sqlite3_finalize((sqlite3_stmt *) svm);
+#endif
+#endif
+ throwoom(env, "unable to get SQLite handle");
+ return;
+ }
+ v->next = h->vms;
+ h->vms = v;
+ v->vm = svm;
+ v->h = h;
+ v->tail = (char *) (v + 1);
+#if HAVE_BOTH_SQLITE
+ v->is3 = v->hh.is3 = h->is3;
+#endif
+ strcpy(v->tail, tail);
+ v->hh.sqlite = 0;
+ v->hh.haveutf = h->haveutf;
+ v->hh.ver = h->ver;
+ v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0;
+ v->hh.row1 = 1;
+ v->hh.enc = h->enc;
+ v->hh.funcs = 0;
+ v->hh.vms = 0;
+ v->hh.env = 0;
+ vv.j = 0;
+ vv.l = (jobject) v;
+ (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j);
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database_vm_1compile_1args(JNIEnv *env,
+ jobject obj, jstring sql,
+ jobject vm, jobjectArray args)
+{
+#if HAVE_SQLITE_COMPILE
+#if HAVE_SQLITE3
+ handle *h = gethandle(env, obj);
+#endif
+
+#if HAVE_BOTH_SQLITE
+ if (h && !h->is3) {
+ throwex(env, "unsupported");
+ return;
+ }
+#else
+#if HAVE_SQLITE2
+ throwex(env, "unsupported");
+#endif
+#endif
+#if HAVE_SQLITE3
+ if (!h || !h->sqlite) {
+ throwclosed(env);
+ return;
+ }
+ if (!vm) {
+ throwex(env, "null vm");
+ return;
+ }
+ if (!sql) {
+ throwex(env, "null sql");
+ return;
+ } else {
+ void *svm = 0;
+ hvm *v;
+ jvalue vv;
+ jthrowable exc;
+ int rc = SQLITE_ERROR, nargs, i;
+ char *p;
+ const char *str = (*env)->GetStringUTFChars(env, sql, NULL);
+ const char *tail;
+ transstr sqlstr;
+ struct args {
+ char *arg;
+ jobject obj;
+ transstr trans;
+ } *argv = 0;
+ char **cargv = 0;
+
+ p = (char *) str;
+ nargs = 0;
+ while (*p) {
+ if (*p == '%') {
+ ++p;
+ if (*p == 'q' || *p == 'Q' || *p == 's') {
+ nargs++;
+ if (nargs > MAX_PARAMS) {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ throwex(env, "too much SQL parameters");
+ return;
+ }
+ } else if (*p != '%') {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ throwex(env, "bad % specification in query");
+ return;
+ }
+ }
+ ++p;
+ }
+ cargv = malloc((sizeof (*argv) + sizeof (char *)) * MAX_PARAMS);
+ if (!cargv) {
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ throwoom(env, "unable to allocate arg vector");
+ return;
+ }
+ argv = (struct args *) (cargv + MAX_PARAMS);
+ for (i = 0; i < MAX_PARAMS; i++) {
+ cargv[i] = 0;
+ argv[i].arg = 0;
+ argv[i].obj = 0;
+ argv[i].trans.result = argv[i].trans.tofree = 0;
+ }
+ exc = 0;
+ for (i = 0; i < nargs; i++) {
+ jobject so = (*env)->GetObjectArrayElement(env, args, i);
+
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ break;
+ }
+ if (so) {
+ argv[i].obj = so;
+ argv[i].arg = cargv[i] =
+ trans2iso(env, 1, 0, argv[i].obj, &argv[i].trans);
+ }
+ }
+ if (exc) {
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ freep((char **) &cargv);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ return;
+ }
+ h->row1 = 1;
+ trans2iso(env, 1, 0, sql, &sqlstr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (!exc) {
+#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR)
+ char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv);
+#else
+ char *s = sqlite3_mprintf(sqlstr.result,
+ cargv[0], cargv[1],
+ cargv[2], cargv[3],
+ cargv[4], cargv[5],
+ cargv[6], cargv[7],
+ cargv[8], cargv[9],
+ cargv[10], cargv[11],
+ cargv[12], cargv[13],
+ cargv[14], cargv[15],
+ cargv[16], cargv[17],
+ cargv[18], cargv[19],
+ cargv[20], cargv[21],
+ cargv[22], cargv[23],
+ cargv[24], cargv[25],
+ cargv[26], cargv[27],
+ cargv[28], cargv[29],
+ cargv[30], cargv[31]);
+#endif
+ if (!s) {
+ rc = SQLITE_NOMEM;
+ } else {
+#if HAVE_SQLITE3_PREPARE_V2
+ rc = sqlite3_prepare_v2((sqlite3 *) h->sqlite, s, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#else
+ rc = sqlite3_prepare((sqlite3 *) h->sqlite, s, -1,
+ (sqlite3_stmt **) &svm, &tail);
+#endif
+ if (rc != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+ }
+ if (rc != SQLITE_OK) {
+ sqlite3_free(s);
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ freep((char **) &cargv);
+ transfree(&sqlstr);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ setvmerr(env, vm, rc);
+ throwex(env, "error in prepare");
+ return;
+ }
+ v = malloc(sizeof (hvm) + strlen(tail) + 1);
+ if (!v) {
+ sqlite3_free(s);
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ freep((char **) &cargv);
+ transfree(&sqlstr);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ setvmerr(env, vm, SQLITE_NOMEM);
+ throwoom(env, "unable to get SQLite handle");
+ return;
+ }
+ v->next = h->vms;
+ h->vms = v;
+ v->vm = svm;
+ v->h = h;
+ v->tail = (char *) (v + 1);
+#if HAVE_BOTH_SQLITE
+ v->is3 = v->hh.is3 = h->is3;
+#endif
+ strcpy(v->tail, tail);
+ sqlite3_free(s);
+ v->hh.sqlite = 0;
+ v->hh.haveutf = h->haveutf;
+ v->hh.ver = h->ver;
+ v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0;
+ v->hh.row1 = 1;
+ v->hh.enc = h->enc;
+ v->hh.funcs = 0;
+ v->hh.vms = 0;
+ v->hh.env = 0;
+ vv.j = 0;
+ vv.l = (jobject) v;
+ (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j);
+ }
+ for (i = 0; i < nargs; i++) {
+ if (argv[i].obj) {
+ transfree(&argv[i].trans);
+ }
+ }
+ freep((char **) &cargv);
+ transfree(&sqlstr);
+ (*env)->ReleaseStringUTFChars(env, sql, str);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ }
+ }
+#endif
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_FunctionContext_internal_1init(JNIEnv *env, jclass cls)
+{
+ F_SQLite_FunctionContext_handle =
+ (*env)->GetFieldID(env, cls, "handle", "J");
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1progress_1handler(JNIEnv *env, jobject obj, jint n,
+ jobject ph)
+{
+ handle *h = gethandle(env, obj);
+
+ if (h && h->sqlite) {
+ /* CHECK THIS */
+#if HAVE_SQLITE_PROGRESS_HANDLER
+ delglobrefp(env, &h->ph);
+#if HAVE_BOTH_SQLITE
+ if (h->is3) {
+ if (ph) {
+ globrefset(env, ph, &h->ph);
+ sqlite3_progress_handler((sqlite3 *) h->sqlite,
+ n, progresshandler, h);
+ } else {
+ sqlite3_progress_handler((sqlite3 *) h->sqlite,
+ 0, 0, 0);
+ }
+ } else {
+ if (ph) {
+ globrefset(env, ph, &h->ph);
+ sqlite_progress_handler((sqlite *) h->sqlite,
+ n, progresshandler, h);
+ } else {
+ sqlite_progress_handler((sqlite *) h->sqlite,
+ 0, 0, 0);
+ }
+ }
+#else
+#if HAVE_SQLITE2
+ if (ph) {
+ globrefset(env, ph, &h->ph);
+ sqlite_progress_handler((sqlite *) h->sqlite,
+ n, progresshandler, h);
+ } else {
+ sqlite_progress_handler((sqlite *) h->sqlite,
+ 0, 0, 0);
+ }
+#endif
+#if HAVE_SQLITE3
+ if (ph) {
+ globrefset(env, ph, &h->ph);
+ sqlite3_progress_handler((sqlite3 *) h->sqlite,
+ n, progresshandler, h);
+ } else {
+ sqlite3_progress_handler((sqlite3 *) h->sqlite,
+ 0, 0, 0);
+ }
+#endif
+#endif
+ return;
+#else
+ throwex(env, "unsupported");
+ return;
+#endif
+ }
+ throwclosed(env);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Database_is3(JNIEnv *env, jobject obj)
+{
+#if HAVE_BOTH_SQLITE
+ handle *h = gethandle(env, obj);
+
+ if (h) {
+ return h->is3 ? JNI_TRUE : JNI_FALSE;
+ }
+ return JNI_FALSE;
+#else
+#if HAVE_SQLITE2
+ return JNI_FALSE;
+#endif
+#if HAVE_SQLITE3
+ return JNI_TRUE;
+#endif
+#endif
+}
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Stmt_prepare(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3
+ hvm *v = gethstmt(env, obj);
+ void *svm = 0;
+ char *tail;
+ int ret;
+
+ if (v && v->vm) {
+ sqlite3_finalize((sqlite3_stmt *) v->vm);
+ v->vm = 0;
+ }
+ if (v && v->h && v->h->sqlite) {
+ if (!v->tail) {
+ return JNI_FALSE;
+ }
+ v->h->env = env;
+#if HAVE_SQLITE3_PREPARE16_V2
+ ret = sqlite3_prepare16_v2((sqlite3 *) v->h->sqlite,
+ v->tail, -1, (sqlite3_stmt **) &svm,
+ (const void **) &tail);
+#else
+ ret = sqlite3_prepare16((sqlite3 *) v->h->sqlite,
+ v->tail, -1, (sqlite3_stmt **) &svm,
+ (const void **) &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+ if (ret != SQLITE_OK) {
+ const char *err = sqlite3_errmsg(v->h->sqlite);
+
+ setstmterr(env, obj, ret);
+ v->tail = 0;
+ throwex(env, err ? err : "error in compile/prepare");
+ return JNI_FALSE;
+ }
+ if (!svm) {
+ v->tail = 0;
+ return JNI_FALSE;
+ }
+ v->vm = svm;
+ v->tail = (char *) tail;
+ v->hh.row1 = 1;
+ return JNI_TRUE;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database_stmt_1prepare(JNIEnv *env, jobject obj, jstring sql,
+ jobject stmt)
+{
+#if HAVE_SQLITE3
+ handle *h = gethandle(env, obj);
+ void *svm = 0;
+ hvm *v;
+ jvalue vv;
+ jsize len16;
+ const jchar *sql16, *tail = 0;
+ int ret;
+
+ if (!h) {
+ throwclosed(env);
+ return;
+ }
+ if (!stmt) {
+ throwex(env, "null stmt");
+ return;
+ }
+ if (!sql) {
+ throwex(env, "null sql");
+ return;
+ }
+#ifdef HAVE_BOTH_SQLITE
+ if (!h->is3) {
+ throwex(env, "only on SQLite3 database");
+ return;
+ }
+#endif
+ len16 = (*env)->GetStringLength(env, sql) * sizeof (jchar);
+ if (len16 < 1) {
+ return;
+ }
+ h->env = env;
+ sql16 = (*env)->GetStringChars(env, sql, 0);
+#if HAVE_SQLITE3_PREPARE16_V2
+ ret = sqlite3_prepare16_v2((sqlite3 *) h->sqlite, sql16, len16,
+ (sqlite3_stmt **) &svm, (const void **) &tail);
+#else
+ ret = sqlite3_prepare16((sqlite3 *) h->sqlite, sql16, len16,
+ (sqlite3_stmt **) &svm, (const void **) &tail);
+#endif
+ if (ret != SQLITE_OK) {
+ if (svm) {
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ svm = 0;
+ }
+ }
+ if (ret != SQLITE_OK) {
+ const char *err = sqlite3_errmsg(h->sqlite);
+
+ (*env)->ReleaseStringChars(env, sql, sql16);
+ setstmterr(env, stmt, ret);
+ throwex(env, err ? err : "error in prepare");
+ return;
+ }
+ if (!svm) {
+ (*env)->ReleaseStringChars(env, sql, sql16);
+ return;
+ }
+ len16 = len16 + sizeof (jchar) - ((char *) tail - (char *) sql16);
+ if (len16 < (jsize) sizeof (jchar)) {
+ len16 = sizeof (jchar);
+ }
+ v = malloc(sizeof (hvm) + len16);
+ if (!v) {
+ (*env)->ReleaseStringChars(env, sql, sql16);
+ sqlite3_finalize((sqlite3_stmt *) svm);
+ throwoom(env, "unable to get SQLite handle");
+ return;
+ }
+ v->next = h->vms;
+ h->vms = v;
+ v->vm = svm;
+ v->h = h;
+ v->tail = (char *) (v + 1);
+#if HAVE_BOTH_SQLITE
+ v->is3 = v->hh.is3 = 1;
+#endif
+ memcpy(v->tail, tail, len16);
+ len16 /= sizeof (jchar);
+ ((jchar *) v->tail)[len16 - 1] = 0;
+ (*env)->ReleaseStringChars(env, sql, sql16);
+ v->hh.sqlite = 0;
+ v->hh.haveutf = h->haveutf;
+ v->hh.ver = h->ver;
+ v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0;
+ v->hh.row1 = 1;
+ v->hh.enc = h->enc;
+ v->hh.funcs = 0;
+ v->hh.vms = 0;
+ v->hh.env = 0;
+ vv.j = 0;
+ vv.l = (jobject) v;
+ (*env)->SetLongField(env, stmt, F_SQLite_Stmt_handle, vv.j);
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT jboolean JNICALL
+Java_SQLite_Stmt_step(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ret;
+
+ ret = sqlite3_step((sqlite3_stmt *) v->vm);
+ if (ret == SQLITE_ROW) {
+ return JNI_TRUE;
+ }
+ if (ret != SQLITE_DONE) {
+ const char *err = sqlite3_errmsg(v->h->sqlite);
+
+ setstmterr(env, obj, ret);
+ throwex(env, err ? err : "error in step");
+ }
+ return JNI_FALSE;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_close(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ret;
+
+ ret = sqlite3_finalize((sqlite3_stmt *) v->vm);
+ v->vm = 0;
+ if (ret != SQLITE_OK) {
+ const char *err = sqlite3_errmsg(v->h->sqlite);
+
+ setstmterr(env, obj, ret);
+ throwex(env, err ? err : "error in close");
+ }
+ return;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_reset(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ sqlite3_reset((sqlite3_stmt *) v->vm);
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_clear_1bindings(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_CLEAR_BINDINGS
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ sqlite3_clear_bindings((sqlite3_stmt *) v->vm);
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__II(JNIEnv *env, jobject obj, jint pos, jint val)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ ret = sqlite3_bind_int((sqlite3_stmt *) v->vm, pos, val);
+ if (ret != SQLITE_OK) {
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__IJ(JNIEnv *env, jobject obj, jint pos, jlong val)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ ret = sqlite3_bind_int64((sqlite3_stmt *) v->vm, pos, val);
+ if (ret != SQLITE_OK) {
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__ID(JNIEnv *env, jobject obj, jint pos, jdouble val)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ ret = sqlite3_bind_double((sqlite3_stmt *) v->vm, pos, val);
+ if (ret != SQLITE_OK) {
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__I_3B(JNIEnv *env, jobject obj, jint pos, jbyteArray val)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+ jint len;
+ char *data = 0;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ if (val) {
+ len = (*env)->GetArrayLength(env, val);
+ if (len > 0) {
+ data = sqlite3_malloc(len);
+ if (!data) {
+ throwoom(env, "unable to get blob parameter");
+ return;
+ }
+ (*env)->GetByteArrayRegion(env, val, 0, len, (jbyte *) data);
+ ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm,
+ pos, data, len, sqlite3_free);
+ } else {
+ ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm,
+ pos, "", 0, SQLITE_STATIC);
+ }
+ } else {
+ ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos);
+ }
+ if (ret != SQLITE_OK) {
+ if (data) {
+ sqlite3_free(data);
+ }
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__ILjava_lang_String_2(JNIEnv *env, jobject obj,
+ jint pos, jstring val)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+ jsize len;
+ char *data = 0;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ if (val) {
+ const jsize charCount = (*env)->GetStringLength(env, val);
+ len = charCount * sizeof(jchar);
+ if (len > 0) {
+ data = sqlite3_malloc(len);
+ if (!data) {
+ throwoom(env, "unable to get blob parameter");
+ return;
+ }
+
+ (*env)->GetStringRegion(env, val, 0, charCount, (jchar*) data);
+ ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm,
+ pos, data, len, sqlite3_free);
+ } else {
+ ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm, pos, "", 0,
+ SQLITE_STATIC);
+ }
+ } else {
+ ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos);
+ }
+ if (ret != SQLITE_OK) {
+ if (data) {
+ sqlite3_free(data);
+ }
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind__I(JNIEnv *env, jobject obj, jint pos)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos);
+ if (ret != SQLITE_OK) {
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_bind_1zeroblob(JNIEnv *env, jobject obj, jint pos, jint len)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_ZEROBLOB
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ int ret;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return;
+ }
+ ret = sqlite3_bind_zeroblob((sqlite3_stmt *) v->vm, pos, len);
+ if (ret != SQLITE_OK) {
+ setstmterr(env, obj, ret);
+ throwex(env, "bind failed");
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Stmt_bind_1parameter_1count(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ return sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_bind_1parameter_1name(JNIEnv *env, jobject obj, jint pos)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_NAME
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm);
+ const char *name;
+
+ if (pos < 1 || pos > npar) {
+ throwex(env, "parameter position out of bounds");
+ return 0;
+ }
+ name = sqlite3_bind_parameter_name((sqlite3_stmt *) v->vm, pos);
+ if (name) {
+ return (*env)->NewStringUTF(env, name);
+ }
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Stmt_bind_1parameter_1index(JNIEnv *env, jobject obj,
+ jstring name)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_INDEX
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int pos;
+ const char *n;
+ transstr namestr;
+ jthrowable exc;
+
+ n = trans2iso(env, 1, 0, name, &namestr);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return -1;
+ }
+ pos = sqlite3_bind_parameter_index((sqlite3_stmt *) v->vm, n);
+ transfree(&namestr);
+ return pos;
+ } else {
+ throwex(env, "stmt already closed");
+ }
+#else
+ throwex(env, "unsupported");
+#endif
+ return -1;
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Stmt_column_1int(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ return sqlite3_column_int((sqlite3_stmt *) v->vm, col);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jlong JNICALL
+Java_SQLite_Stmt_column_1long(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ return sqlite3_column_int64((sqlite3_stmt *) v->vm, col);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_SQLite_Stmt_column_1double(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ return sqlite3_column_double((sqlite3_stmt *) v->vm, col);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_SQLite_Stmt_column_1bytes(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+ int nbytes;
+ const jbyte *data;
+ jbyteArray b = 0;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ data = sqlite3_column_blob((sqlite3_stmt *) v->vm, col);
+ if (data) {
+ nbytes = sqlite3_column_bytes((sqlite3_stmt *) v->vm, col);
+ } else {
+ return 0;
+ }
+ b = (*env)->NewByteArray(env, nbytes);
+ if (!b) {
+ throwoom(env, "unable to get blob column data");
+ return 0;
+ }
+ (*env)->SetByteArrayRegion(env, b, 0, nbytes, data);
+ return b;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_column_1string(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+ int nbytes;
+ const jchar *data;
+ jstring b = 0;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ data = sqlite3_column_text16((sqlite3_stmt *) v->vm, col);
+ if (data) {
+ nbytes = sqlite3_column_bytes16((sqlite3_stmt *) v->vm, col);
+ } else {
+ return 0;
+ }
+ nbytes /= sizeof (jchar);
+ b = (*env)->NewString(env, data, nbytes);
+ if (!b) {
+ throwoom(env, "unable to get string column data");
+ return 0;
+ }
+ return b;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Stmt_column_1type(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm);
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ return sqlite3_column_type((sqlite3_stmt *) v->vm, col);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Stmt_column_1count(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ return sqlite3_column_count((sqlite3_stmt *) v->vm);
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_column_1table_1name(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_TABLE_NAME16
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm);
+ const jchar *str;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ str = sqlite3_column_table_name16((sqlite3_stmt *) v->vm, col);
+ if (str) {
+ return (*env)->NewString(env, str, jstrlen(str));
+ }
+ return 0;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_column_1database_1name(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_DATABASE_NAME16
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm);
+ const jchar *str;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ str = sqlite3_column_database_name16((sqlite3_stmt *) v->vm, col);
+ if (str) {
+ return (*env)->NewString(env, str, jstrlen(str));
+ }
+ return 0;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_column_1decltype(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm);
+ const jchar *str;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ str = sqlite3_column_decltype16((sqlite3_stmt *) v->vm, col);
+ if (str) {
+ return (*env)->NewString(env, str, jstrlen(str));
+ }
+ return 0;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jstring JNICALL
+Java_SQLite_Stmt_column_1origin_1name(JNIEnv *env, jobject obj, jint col)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_ORIGIN_NAME16
+ hvm *v = gethstmt(env, obj);
+
+ if (v && v->vm && v->h) {
+ int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm);
+ const jchar *str;
+
+ if (col < 0 || col >= ncol) {
+ throwex(env, "column out of bounds");
+ return 0;
+ }
+ str = sqlite3_column_origin_name16((sqlite3_stmt *) v->vm, col);
+ if (str) {
+ return (*env)->NewString(env, str, jstrlen(str));
+ }
+ return 0;
+ }
+ throwex(env, "stmt already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_finalize(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE
+ dostmtfinal(env, obj);
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database__1open_1blob(JNIEnv *env, jobject obj,
+ jstring dbname, jstring table,
+ jstring column, jlong row,
+ jboolean rw, jobject blobj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ handle *h = gethandle(env, obj);
+ hbl *bl;
+ jthrowable exc;
+ transstr dbn, tbl, col;
+ sqlite3_blob *blob;
+ jvalue vv;
+ int ret;
+
+ if (!blobj) {
+ throwex(env, "null blob");
+ return;
+ }
+ if (h && h->sqlite) {
+ trans2iso(env, h->haveutf, h->enc, dbname, &dbn);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ trans2iso(env, h->haveutf, h->enc, table, &tbl);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ transfree(&dbn);
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ trans2iso(env, h->haveutf, h->enc, column, &col);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ transfree(&tbl);
+ transfree(&dbn);
+ (*env)->DeleteLocalRef(env, exc);
+ return;
+ }
+ ret = sqlite3_blob_open(h->sqlite,
+ dbn.result, tbl.result, col.result,
+ row, rw, &blob);
+ transfree(&col);
+ transfree(&tbl);
+ transfree(&dbn);
+ if (ret != SQLITE_OK) {
+ const char *err = sqlite3_errmsg(h->sqlite);
+
+ seterr(env, obj, ret);
+ throwex(env, err ? err : "error in blob open");
+ return;
+ }
+ bl = malloc(sizeof (hbl));
+ if (!bl) {
+ sqlite3_blob_close(blob);
+ throwoom(env, "unable to get SQLite blob handle");
+ return;
+ }
+ bl->next = h->blobs;
+ h->blobs = bl;
+ bl->blob = blob;
+ bl->h = h;
+ vv.j = 0;
+ vv.l = (jobject) bl;
+ (*env)->SetLongField(env, blobj, F_SQLite_Blob_handle, vv.j);
+ (*env)->SetIntField(env, blobj, F_SQLite_Blob_size,
+ sqlite3_blob_bytes(blob));
+ return;
+ }
+ throwex(env, "not an open database");
+#else
+ throwex(env, "unsupported");
+#endif
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Blob_write(JNIEnv *env , jobject obj, jbyteArray b, jint off,
+ jint pos, jint len)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ hbl *bl = gethbl(env, obj);
+
+ if (bl && bl->h && bl->blob) {
+ jbyte *buf;
+ jthrowable exc;
+ int ret;
+
+ if (len <= 0) {
+ return 0;
+ }
+ buf = malloc(len);
+ if (!buf) {
+ throwoom(env, "out of buffer space for blob");
+ return 0;
+ }
+ (*env)->GetByteArrayRegion(env, b, off, len, buf);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ free(buf);
+ return 0;
+ }
+ ret = sqlite3_blob_write(bl->blob, buf, len, pos);
+ free(buf);
+ if (ret != SQLITE_OK) {
+ throwioex(env, "blob write error");
+ return 0;
+ }
+ return len;
+ }
+ throwex(env, "blob already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_SQLite_Blob_read(JNIEnv *env , jobject obj, jbyteArray b, jint off,
+ jint pos, jint len)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ hbl *bl = gethbl(env, obj);
+
+ if (bl && bl->h && bl->blob) {
+ jbyte *buf;
+ jthrowable exc;
+ int ret;
+
+ if (len <= 0) {
+ return 0;
+ }
+ buf = malloc(len);
+ if (!buf) {
+ throwoom(env, "out of buffer space for blob");
+ return 0;
+ }
+ ret = sqlite3_blob_read(bl->blob, buf, len, pos);
+ if (ret != SQLITE_OK) {
+ free(buf);
+ throwioex(env, "blob read error");
+ return 0;
+ }
+ (*env)->SetByteArrayRegion(env, b, off, len, buf);
+ free(buf);
+ exc = (*env)->ExceptionOccurred(env);
+ if (exc) {
+ return 0;
+ }
+ return len;
+ }
+ throwex(env, "blob already closed");
+#else
+ throwex(env, "unsupported");
+#endif
+ return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Blob_close(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ doblobfinal(env, obj);
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Blob_finalize(JNIEnv *env, jobject obj)
+{
+#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO
+ doblobfinal(env, obj);
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Stmt_internal_1init(JNIEnv *env, jclass cls)
+{
+ F_SQLite_Stmt_handle =
+ (*env)->GetFieldID(env, cls, "handle", "J");
+ F_SQLite_Stmt_error_code =
+ (*env)->GetFieldID(env, cls, "error_code", "I");
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Vm_internal_1init(JNIEnv *env, jclass cls)
+{
+ F_SQLite_Vm_handle =
+ (*env)->GetFieldID(env, cls, "handle", "J");
+ F_SQLite_Vm_error_code =
+ (*env)->GetFieldID(env, cls, "error_code", "I");
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Blob_internal_1init(JNIEnv *env, jclass cls)
+{
+ F_SQLite_Blob_handle =
+ (*env)->GetFieldID(env, cls, "handle", "J");
+ F_SQLite_Blob_size =
+ (*env)->GetFieldID(env, cls, "size", "I");
+}
+
+JNIEXPORT void JNICALL
+Java_SQLite_Database_internal_1init(JNIEnv *env, jclass cls)
+{
+//#ifndef JNI_VERSION_1_2
+ jclass jls = (*env)->FindClass(env, "java/lang/String");
+
+ C_java_lang_String = (*env)->NewGlobalRef(env, jls);
+//#endif
+ F_SQLite_Database_handle =
+ (*env)->GetFieldID(env, cls, "handle", "J");
+ F_SQLite_Database_error_code =
+ (*env)->GetFieldID(env, cls, "error_code", "I");
+ M_java_lang_String_getBytes =
+ (*env)->GetMethodID(env, C_java_lang_String, "getBytes", "()[B");
+ M_java_lang_String_getBytes2 =
+ (*env)->GetMethodID(env, C_java_lang_String, "getBytes",
+ "(Ljava/lang/String;)[B");
+ M_java_lang_String_initBytes =
+ (*env)->GetMethodID(env, C_java_lang_String, "<init>", "([B)V");
+ M_java_lang_String_initBytes2 =
+ (*env)->GetMethodID(env, C_java_lang_String, "<init>",
+ "([BLjava/lang/String;)V");
+}
+
+#ifdef JNI_VERSION_1_2
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+ jclass cls;
+
+#ifndef _WIN32
+#if HAVE_SQLITE2
+ if (strcmp(sqlite_libencoding(), "UTF-8") != 0) {
+ fprintf(stderr, "WARNING: using non-UTF SQLite2 engine\n");
+ }
+#endif
+#endif
+ if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) {
+ return JNI_ERR;
+ }
+ cls = (*env)->FindClass(env, "java/lang/String");
+ if (!cls) {
+ return JNI_ERR;
+ }
+ C_java_lang_String = (*env)->NewWeakGlobalRef(env, cls);
+ return JNI_VERSION_1_2;
+}
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+
+ if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) {
+ return;
+ }
+ if (C_java_lang_String) {
+ (*env)->DeleteWeakGlobalRef(env, C_java_lang_String);
+ C_java_lang_String = 0;
+ }
+}
+#endif