mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-17 01:26:25 +00:00
5038 lines
111 KiB
C
5038 lines
111 KiB
C
#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;
|
|
#if HAVE_SQLITE2
|
|
int tmp;
|
|
#endif
|
|
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[1], 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[1], 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
|