| #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 |
| |
| #ifndef HAVE_SQLITE3_SHARED_CACHE |
| #define HAVE_SQLITE3_SHARED_CACHE 0 |
| #endif |
| |
| #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 pr; /* Profile 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 |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| struct hbk *backups; /* SQLite3 backup 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 |
| |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| /* internal handle for sqlite3_backup */ |
| |
| typedef struct hbk { |
| struct hbk *next; /* next blob handle */ |
| sqlite3_backup *bkup; /* SQLite3 backup handle */ |
| handle *h; /* SQLite database handle (source) */ |
| } hbk; |
| #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 jfieldID F_SQLite_Backup_handle = 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 |
| |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| static void * |
| gethbk(JNIEnv *env, jobject obj) |
| { |
| jvalue v; |
| |
| v.j = (*env)->GetLongField(env, obj, F_SQLite_Backup_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) { |
| #ifndef JNI_VERSION_1_2 |
| const char *utf = (*env)->GetStringUTFChars(env, src, 0); |
| |
| dest->result = dest->tofree = malloc(strlen(utf) + 1); |
| #else |
| jsize utflen = (*env)->GetStringUTFLength(env, src); |
| jsize uclen = (*env)->GetStringLength(env, src); |
| |
| dest->result = dest->tofree = malloc(utflen + 1); |
| #endif |
| if (!dest->tofree) { |
| throwoom(env, "string translation failed"); |
| return dest->result; |
| } |
| #ifndef JNI_VERSION_1_2 |
| strcpy(dest->result, utf); |
| (*env)->ReleaseStringUTFChars(env, src, utf); |
| #else |
| (*env)->GetStringUTFRegion(env, src, 0, uclen, dest->result); |
| dest->result[utflen] = '\0'; |
| #endif |
| 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 |
| } |
| if (data) { |
| mid = (*env)->GetMethodID(env, cls, "newrow", |
| "([Ljava/lang/String;)Z"); |
| if (mid) { |
| jboolean rc; |
| |
| arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 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_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| hbk *bk; |
| #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 |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| while ((bk = h->backups)) { |
| h->backups = bk->next; |
| bk->next = 0; |
| bk->h = 0; |
| if (bk->bkup) { |
| sqlite3_backup_finish(bk->bkup); |
| } |
| bk->bkup = 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__1open4(JNIEnv *env, jobject obj, jstring file, jint mode, |
| jstring vfs, jboolean ver2) |
| { |
| handle *h = gethandle(env, obj); |
| jthrowable exc; |
| char *err = 0; |
| transstr filename; |
| int maj, min, lev; |
| #if HAVE_SQLITE3_OPEN_V2 |
| transstr vfsname; |
| |
| vfsname.result = 0; |
| vfsname.tofree = 0; |
| vfsname.jstr = 0; |
| #endif |
| |
| 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->pr = 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 |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| h->backups = 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_SQLITE3_OPEN_V2 |
| if (vfs) { |
| trans2iso(env, 1, h->enc, vfs, &vfsname); |
| exc = (*env)->ExceptionOccurred(env); |
| if (exc) { |
| transfree(&filename); |
| (*env)->DeleteLocalRef(env, exc); |
| return; |
| } |
| } |
| #endif |
| #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 != '*' && ver2 == JNI_FALSE) { |
| #if HAVE_SQLITE3_OPEN_V2 |
| int rc = sqlite3_open_v2(filename.result, (sqlite3 **) &h->sqlite, |
| (int) mode, vfsname.result); |
| #else |
| int rc = sqlite3_open(filename.result, (sqlite3 **) &h->sqlite); |
| #endif |
| |
| 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 HAVE_SQLITE3_OPEN_V2 |
| if (sqlite3_open_v2(filename.result, (sqlite3 **) &h->sqlite, |
| (int) mode, vfsname.result) != SQLITE_OK) |
| #else |
| if (sqlite3_open(filename.result, (sqlite3 **) &h->sqlite) != SQLITE_OK) |
| #endif |
| { |
| if (h->sqlite) { |
| sqlite3_close((sqlite3 *) h->sqlite); |
| h->sqlite = 0; |
| } |
| } |
| #endif |
| #endif |
| transfree(&filename); |
| #if HAVE_SQLITE3_OPEN_V2 |
| transfree(&vfsname); |
| #endif |
| 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); |
| #if HAVE_SQLITE3_LOAD_EXTENSION |
| sqlite3_enable_load_extension((sqlite3 *) h->sqlite, 1); |
| #endif |
| } 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); |
| #if HAVE_SQLITE3_LOAD_EXTENSION |
| sqlite3_enable_load_extension((sqlite3 *) h->sqlite, 1); |
| #endif |
| #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(JNIEnv *env, jobject obj, jstring file, jint mode) |
| { |
| Java_SQLite_Database__1open4(env, obj, file, mode, 0, 0); |
| } |
| |
| 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 |
| 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, 0); |
| 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, tmp; |
| long 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_DONE && v->hh.row1) { |
| ncol = sqlite3_column_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); |
| } |
| } |
| } else 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 { |
| tmp = 0; |
| ret = sqlite_step((sqlite_vm *) v->vm, &tmp, &data, &cols); |
| ncol = tmp; |
| } |
| #else |
| #if HAVE_SQLITE2 |
| tmp = 0; |
| ret = sqlite_step((sqlite_vm *) v->vm, &tmp, &data, &cols); |
| ncol = tmp; |
| #endif |
| #if HAVE_SQLITE3 |
| ret = sqlite3_step((sqlite3_stmt *) v->vm); |
| if (ret == SQLITE_DONE && v->hh.row1) { |
| ncol = sqlite3_column_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); |
| } |
| } |
| } else 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 (v->hh.row1 && cols) { |
| 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 **) 0, (char **) cols); |
| #if HAVE_SQLITE3 |
| if (data && freeproc) { |
| freeproc((void *) data); |
| } |
| #endif |
| exc = (*env)->ExceptionOccurred(env); |
| if (exc) { |
| (*env)->DeleteLocalRef(env, exc); |
| } |
| } |
| #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; |
| #ifdef HAVE_SQLITE2 |
| char *errfr = 0; |
| #endif |
| 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; |
| } |
| err = (char *) sqlite3_errmsg((sqlite3 *) v->h->sqlite); |
| } |
| } else { |
| ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail, |
| &tail, (sqlite_vm **) &svm, &errfr); |
| if (ret != SQLITE_OK) { |
| err = errfr; |
| 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, &errfr); |
| if (ret != SQLITE_OK) { |
| err = errfr; |
| 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; |
| } |
| err = (char *) sqlite3_errmsg((sqlite3 *) v->h->sqlite); |
| } |
| #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 (errfr) { |
| sqlite_freemem(errfr); |
| } |
| #endif |
| return JNI_FALSE; |
| } |
| #if HAVE_SQLITE2 |
| if (errfr) { |
| sqlite_freemem(errfr); |
| } |
| #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; |
| #if HAVE_SQLITE2 |
| char *errfr = 0; |
| #endif |
| 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; |
| } |
| err = (char *) sqlite3_errmsg((sqlite3 *) h->sqlite); |
| } |
| } else { |
| ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, |
| (sqlite_vm **) &svm, &errfr); |
| if (ret != SQLITE_OK) { |
| err = errfr; |
| if (svm) { |
| sqlite_finalize((sqlite_vm *) svm, 0); |
| } |
| } |
| } |
| #else |
| #if HAVE_SQLITE2 |
| ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, |
| (sqlite_vm **) &svm, &errfr); |
| if (ret != SQLITE_OK) { |
| err = errfr; |
| 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; |
| } |
| err = (char *) sqlite3_errmsg((sqlite3 *) h->sqlite); |
| } |
| #endif |
| #endif |
| if (ret != SQLITE_OK) { |
| transfree(&tr); |
| setvmerr(env, vm, ret); |
| throwex(env, err ? err : "error in prepare/compile"); |
| #if HAVE_SQLITE2 |
| if (errfr) { |
| sqlite_freemem(errfr); |
| } |
| #endif |
| return; |
| } |
| #if HAVE_SQLITE2 |
| if (errfr) { |
| sqlite_freemem(errfr); |
| } |
| #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, 0); |
| 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 < 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, count; |
| char *data = 0; |
| |
| if (pos < 1 || pos > npar) { |
| throwex(env, "parameter position out of bounds"); |
| return; |
| } |
| if (val) { |
| count = (*env)->GetStringLength(env, val); |
| len = count * sizeof (jchar); |
| if (len > 0) { |
| #ifndef JNI_VERSION_1_2 |
| const jchar *ch; |
| #endif |
| data = sqlite3_malloc(len); |
| if (!data) { |
| throwoom(env, "unable to get blob parameter"); |
| return; |
| } |
| #ifndef JNI_VERSION_1_2 |
| ch = (*env)->GetStringChars(env, val, 0); |
| memcpy(data, ch, len); |
| (*env)->ReleaseStringChars(env, val, ch); |
| #else |
| (*env)->GetStringRegion(env, val, 0, count, (jchar *) data); |
| #endif |
| 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 jint JNICALL |
| Java_SQLite_Stmt_status(JNIEnv *env, jobject obj, jint op, jboolean flg) |
| { |
| jint count = 0; |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_STMT_STATUS |
| hvm *v = gethstmt(env, obj); |
| |
| if (v && v->vm && v->h) { |
| count = sqlite3_stmt_status((sqlite3_stmt *) v->vm, op, |
| flg == JNI_TRUE); |
| } |
| #endif |
| return count; |
| } |
| |
| 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 HAVE_BOTH_SQLITE |
| if (!h->is3) { |
| throwex(env, "not a SQLite 3 database"); |
| return; |
| } |
| #endif |
| 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_Database__1key(JNIEnv *env, jobject obj, jbyteArray key) |
| { |
| jsize len; |
| jbyte *data; |
| #if HAVE_SQLITE3_KEY |
| handle *h = gethandle(env, obj); |
| #endif |
| |
| len = (*env)->GetArrayLength(env, key); |
| data = (*env)->GetByteArrayElements(env, key, 0); |
| if (len == 0) { |
| data = 0; |
| } |
| if (!data) { |
| len = 0; |
| } |
| #if HAVE_SQLITE3_KEY |
| if (h && h->sqlite) { |
| #if HAVE_BOTH_SQLITE |
| if (!h->is3) { |
| if (data) { |
| memset(data, 0, len); |
| } |
| throwex(env, "unsupported"); |
| } |
| #endif |
| sqlite3_key((sqlite3 *) h->sqlite, data, len); |
| if (data) { |
| memset(data, 0, len); |
| } |
| } else { |
| if (data) { |
| memset(data, 0, len); |
| } |
| throwclosed(env); |
| } |
| #else |
| if (data) { |
| memset(data, 0, len); |
| } |
| /* no error */ |
| #endif |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_SQLite_Database__1rekey(JNIEnv *env, jobject obj, jbyteArray key) |
| { |
| jsize len; |
| jbyte *data; |
| #if HAVE_SQLITE3_KEY |
| handle *h = gethandle(env, obj); |
| #endif |
| |
| len = (*env)->GetArrayLength(env, key); |
| data = (*env)->GetByteArrayElements(env, key, 0); |
| if (len == 0) { |
| data = 0; |
| } |
| if (!data) { |
| len = 0; |
| } |
| #if HAVE_SQLITE3_KEY |
| if (h && h->sqlite) { |
| #if HAVE_BOTH_SQLITE |
| if (!h->is3) { |
| if (data) { |
| memset(data, 0, len); |
| } |
| throwex(env, "unsupported"); |
| } |
| #endif |
| sqlite3_rekey((sqlite3 *) h->sqlite, data, len); |
| if (data) { |
| memset(data, 0, len); |
| } |
| } else { |
| if (data) { |
| memset(data, 0, len); |
| } |
| throwclosed(env); |
| } |
| #else |
| if (data) { |
| memset(data, 0, len); |
| } |
| throwex(env, "unsupported"); |
| #endif |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_SQLite_Database__1enable_1shared_1cache(JNIEnv *env, jclass cls, |
| jboolean onoff) |
| { |
| #if HAVE_SQLITE3_SHARED_CACHE |
| return (sqlite3_enable_shared_cache(onoff == JNI_TRUE) == SQLITE_OK) ? |
| JNI_TRUE : JNI_FALSE; |
| #else |
| return JNI_FALSE; |
| #endif |
| } |
| |
| |
| JNIEXPORT void JNICALL |
| Java_SQLite_Database__1backup(JNIEnv *env, jclass cls, jobject bkupj, |
| jobject dest, jstring destName, |
| jobject src, jstring srcName) |
| { |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| handle *hsrc = gethandle(env, src); |
| handle *hdest = gethandle(env, dest); |
| hbk *bk; |
| jthrowable exc; |
| transstr dbns, dbnd; |
| sqlite3_backup *bkup; |
| jvalue vv; |
| |
| if (!bkupj) { |
| throwex(env, "null backup"); |
| return; |
| } |
| if (!hsrc) { |
| throwex(env, "no source database"); |
| return; |
| } |
| if (!hdest) { |
| throwex(env, "no destination database"); |
| return; |
| } |
| #if HAVE_BOTH_SQLITE |
| if (!hsrc->is3 || !hdest->is3) { |
| throwex(env, "not a SQLite 3 database"); |
| return; |
| } |
| #endif |
| if (!hsrc->sqlite) { |
| throwex(env, "source database not open"); |
| return; |
| } |
| if (!hdest->sqlite) { |
| throwex(env, "destination database not open"); |
| return; |
| } |
| trans2iso(env, hdest->haveutf, hdest->enc, destName, &dbnd); |
| exc = (*env)->ExceptionOccurred(env); |
| if (exc) { |
| (*env)->DeleteLocalRef(env, exc); |
| return; |
| } |
| trans2iso(env, hsrc->haveutf, hsrc->enc, srcName, &dbns); |
| exc = (*env)->ExceptionOccurred(env); |
| if (exc) { |
| transfree(&dbnd); |
| (*env)->DeleteLocalRef(env, exc); |
| return; |
| } |
| bkup = sqlite3_backup_init((sqlite3 *) hdest->sqlite, dbnd.result, |
| (sqlite3 *) hsrc->sqlite, dbns.result); |
| transfree(&dbnd); |
| transfree(&dbns); |
| if (!bkup) { |
| const char *err = sqlite3_errmsg((sqlite3 *) hdest->sqlite); |
| |
| seterr(env, src, sqlite3_errcode((sqlite3 *) hdest->sqlite)); |
| throwex(env, err ? err : "error in backup init"); |
| return; |
| } |
| bk = malloc(sizeof (hbk)); |
| if (!bk) { |
| sqlite3_backup_finish(bkup); |
| throwoom(env, "unable to get SQLite backup handle"); |
| return; |
| } |
| bk->next = hsrc->backups; |
| hsrc->backups = bk; |
| bk->bkup = bkup; |
| bk->h = hsrc; |
| vv.j = 0; |
| vv.l = (jobject) bk; |
| (*env)->SetLongField(env, bkupj, F_SQLite_Backup_handle, vv.j); |
| return; |
| #else |
| throwex(env, "unsupported"); |
| #endif |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_SQLite_Backup__1finalize(JNIEnv *env, jobject obj) |
| { |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| hbk *bk = gethbk(env, obj); |
| int ret = SQLITE_OK; |
| char *err = 0; |
| |
| if (bk) { |
| if (bk->h) { |
| handle *h = bk->h; |
| hbk *bkc, **bkp; |
| |
| bkp = &h->backups; |
| bkc = *bkp; |
| while (bkc) { |
| if (bkc == bk) { |
| *bkp = bkc->next; |
| break; |
| } |
| bkp = &bkc->next; |
| bkc = *bkp; |
| } |
| } |
| if (bk->bkup) { |
| ret = sqlite3_backup_finish(bk->bkup); |
| if (ret != SQLITE_OK && bk->h) { |
| err = (char *) sqlite3_errmsg((sqlite3 *) bk->h->sqlite); |
| } |
| } |
| bk->bkup = 0; |
| free(bk); |
| (*env)->SetLongField(env, obj, F_SQLite_Backup_handle, 0); |
| if (ret != SQLITE_OK) { |
| throwex(env, err ? err : "unknown error"); |
| } |
| } |
| #endif |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_SQLite_Backup__1step(JNIEnv *env, jobject obj, jint n) |
| { |
| jboolean result = JNI_TRUE; |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| hbk *bk = gethbk(env, obj); |
| int ret; |
| |
| if (bk) { |
| if (bk->bkup) { |
| ret = sqlite3_backup_step(bk->bkup, (int) n); |
| switch (ret) { |
| case SQLITE_DONE: |
| break; |
| case SQLITE_LOCKED: |
| case SQLITE_BUSY: |
| case SQLITE_OK: |
| result = JNI_FALSE; |
| break; |
| default: |
| result = JNI_FALSE; |
| throwex(env, "backup step failed"); |
| break; |
| } |
| } |
| } else { |
| throwex(env, "stale backup object"); |
| } |
| #else |
| throwex(env, "unsupported"); |
| #endif |
| return result; |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_SQLite_Backup__1remaining(JNIEnv *env, jobject obj) |
| { |
| jint result = 0; |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| hbk *bk = gethbk(env, obj); |
| |
| if (bk) { |
| if (bk->bkup) { |
| result = sqlite3_backup_remaining(bk->bkup); |
| } |
| } |
| #else |
| throwex(env, "unsupported"); |
| #endif |
| return result; |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_SQLite_Backup__1pagecount(JNIEnv *env, jobject obj) |
| { |
| jint result = 0; |
| #if HAVE_SQLITE3 && HAVE_SQLITE3_BACKUPAPI |
| hbk *bk = gethbk(env, obj); |
| |
| if (bk) { |
| if (bk->bkup) { |
| result = sqlite3_backup_pagecount(bk->bkup); |
| } |
| } |
| #else |
| throwex(env, "unsupported"); |
| #endif |
| return result; |
| } |
| |
| #if HAVE_SQLITE3_PROFILE |
| static void |
| doprofile(void *arg, const char *msg, sqlite_uint64 est) |
| { |
| handle *h = (handle *) arg; |
| JNIEnv *env = h->env; |
| |
| if (env && h->pr && msg) { |
| jthrowable exc; |
| jclass cls = (*env)->GetObjectClass(env, h->pr); |
| jmethodID mid; |
| |
| mid = (*env)->GetMethodID(env, cls, "profile", |
| "(Ljava/lang/String;J)V"); |
| if (mid) { |
| transstr tr; |
| #if _MSC_VER && (_MSC_VER < 1300) |
| jlong ms = est / (3600i64 * 24i64 * 1000i64); |
| #else |
| jlong ms = est / (3600LL * 24LL * 1000LL); |
| #endif |
| |
| 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->pr, mid, tr.jstr, ms); |
| (*env)->ExceptionClear(env); |
| (*env)->DeleteLocalRef(env, tr.jstr); |
| return; |
| } |
| } |
| return; |
| } |
| #endif |
| |
| JNIEXPORT void JNICALL |
| Java_SQLite_Database__1profile(JNIEnv *env, jobject obj, jobject tr) |
| { |
| #if HAVE_SQLITE3_PROFILE |
| handle *h = gethandle(env, obj); |
| |
| if (h && h->sqlite) { |
| delglobrefp(env, &h->pr); |
| globrefset(env, tr, &h->pr); |
| #if HAVE_BOTH_SQLITE |
| if (h->is3) { |
| sqlite3_profile((sqlite3 *) h->sqlite, h->pr ? doprofile : 0, h); |
| } |
| #else |
| #if HAVE_SQLITE3 |
| sqlite3_profile((sqlite3 *) h->sqlite, h->pr ? doprofile : 0, h); |
| #endif |
| #endif |
| } |
| #endif |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_SQLite_Database__1status(JNIEnv *env, jclass cls, jint op, |
| jintArray info, jboolean flag) |
| { |
| jint ret = SQLITE_ERROR; |
| #if HAVE_SQLITE3_STATUS |
| int data[2] = { 0, 0 }; |
| jint jdata[2]; |
| #if HAVE_SQLITE3 |
| ret = sqlite3_status(op, &data[0], &data[2], flag); |
| if (ret == SQLITE_OK) { |
| jdata[0] = data[0]; |
| jdata[1] = data[1]; |
| (*env)->SetIntArrayRegion(env, info, 0, 2, jdata); |
| } |
| #endif |
| #endif |
| return ret; |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_SQLite_Database__1db_1status(JNIEnv *env, jobject obj, jint op, |
| jintArray info, jboolean flag) |
| { |
| jint ret = SQLITE_ERROR; |
| #if HAVE_SQLITE3_DB_STATUS |
| handle *h = gethandle(env, obj); |
| int data[2] = { 0, 0 }; |
| jint jdata[2]; |
| |
| if (h && h->sqlite) { |
| #if HAVE_BOTH_SQLITE |
| if (h->is3) { |
| ret = sqlite3_db_status((sqlite3 *) h->sqlite, op, &data[0], |
| &data[1], flag); |
| } |
| #else |
| #if HAVE_SQLITE3 |
| ret = sqlite3_db_status((sqlite3 *) h->sqlite, op, &data[0], |
| &data[2], flag); |
| #endif |
| #endif |
| if (ret == SQLITE_OK) { |
| jdata[0] = data[0]; |
| jdata[1] = data[1]; |
| (*env)->SetIntArrayRegion(env, info, 0, 2, jdata); |
| } |
| } |
| #endif |
| return ret; |
| } |
| |
| 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_Backup_internal_1init(JNIEnv *env, jclass cls) |
| { |
| F_SQLite_Backup_handle = |
| (*env)->GetFieldID(env, cls, "handle", "J"); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_SQLite_Database_internal_1init(JNIEnv *env, jclass cls) |
| { |
| #if defined(DONT_USE_JNI_ONLOAD) || !defined(JNI_VERSION_1_2) |
| while (C_java_lang_String == 0) { |
| 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"); |
| } |
| |
| #if !defined(DONT_USE_JNI_ONLOAD) && defined(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)->NewGlobalRef(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)->DeleteGlobalRef(env, C_java_lang_String); |
| C_java_lang_String = 0; |
| } |
| } |
| #endif |