diff options
Diffstat (limited to 'core/jni/android_database_SQLiteProgram.cpp')
-rw-r--r-- | core/jni/android_database_SQLiteProgram.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp new file mode 100644 index 0000000..54e7de2 --- /dev/null +++ b/core/jni/android_database_SQLiteProgram.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2006-2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "Cursor" + +#include <jni.h> +#include <JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> + +#include <sqlite3.h> + +#include <utils/Log.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "sqlite3_exception.h" + + +namespace android { + +static jfieldID gHandleField; +static jfieldID gStatementField; + + +#define GET_STATEMENT(env, object) \ + (sqlite3_stmt *)env->GetIntField(object, gStatementField) +#define GET_HANDLE(env, object) \ + (sqlite3 *)env->GetIntField(object, gHandleField) + + +sqlite3_stmt * compile(JNIEnv* env, jobject object, + sqlite3 * handle, jstring sqlString) +{ + int err; + jchar const * sql; + jsize sqlLen; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + // Make sure not to leak the statement if it already exists + if (statement != NULL) { + sqlite3_finalize(statement); + env->SetIntField(object, gStatementField, 0); + } + + // Compile the SQL + sql = env->GetStringChars(sqlString, NULL); + sqlLen = env->GetStringLength(sqlString); + err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL); + env->ReleaseStringChars(sqlString, sql); + + if (err == SQLITE_OK) { + // Store the statement in the Java object for future calls + LOGV("Prepared statement %p on %p", statement, handle); + env->SetIntField(object, gStatementField, (int)statement); + return statement; + } else { + // Error messages like 'near ")": syntax error' are not + // always helpful enough, so construct an error string that + // includes the query itself. + const char *query = env->GetStringUTFChars(sqlString, NULL); + char *message = (char*) malloc(strlen(query) + 50); + if (message) { + strcpy(message, ", while compiling: "); // less than 50 chars + strcat(message, query); + } + env->ReleaseStringUTFChars(sqlString, query); + throw_sqlite3_exception(env, handle, message); + free(message); + return NULL; + } +} + +static void native_compile(JNIEnv* env, jobject object, jstring sqlString) +{ + compile(env, object, GET_HANDLE(env, object), sqlString); +} + +static void native_bind_null(JNIEnv* env, jobject object, + jint index) +{ + int err; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + err = sqlite3_bind_null(statement, index); + if (err != SQLITE_OK) { + char buf[32]; + sprintf(buf, "handle %p", statement); + throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); + return; + } +} + +static void native_bind_long(JNIEnv* env, jobject object, + jint index, jlong value) +{ + int err; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + err = sqlite3_bind_int64(statement, index, value); + if (err != SQLITE_OK) { + char buf[32]; + sprintf(buf, "handle %p", statement); + throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); + return; + } +} + +static void native_bind_double(JNIEnv* env, jobject object, + jint index, jdouble value) +{ + int err; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + err = sqlite3_bind_double(statement, index, value); + if (err != SQLITE_OK) { + char buf[32]; + sprintf(buf, "handle %p", statement); + throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); + return; + } +} + +static void native_bind_string(JNIEnv* env, jobject object, + jint index, jstring sqlString) +{ + int err; + jchar const * sql; + jsize sqlLen; + sqlite3_stmt * statement= GET_STATEMENT(env, object); + + sql = env->GetStringChars(sqlString, NULL); + sqlLen = env->GetStringLength(sqlString); + err = sqlite3_bind_text16(statement, index, sql, sqlLen * 2, SQLITE_TRANSIENT); + env->ReleaseStringChars(sqlString, sql); + if (err != SQLITE_OK) { + char buf[32]; + sprintf(buf, "handle %p", statement); + throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); + return; + } +} + +static void native_bind_blob(JNIEnv* env, jobject object, + jint index, jbyteArray value) +{ + int err; + jchar const * sql; + jsize sqlLen; + sqlite3_stmt * statement= GET_STATEMENT(env, object); + + jint len = env->GetArrayLength(value); + jbyte * bytes = env->GetByteArrayElements(value, NULL); + + err = sqlite3_bind_blob(statement, index, bytes, len, SQLITE_TRANSIENT); + env->ReleaseByteArrayElements(value, bytes, JNI_ABORT); + + if (err != SQLITE_OK) { + char buf[32]; + sprintf(buf, "handle %p", statement); + throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); + return; + } +} + +static void native_clear_bindings(JNIEnv* env, jobject object) +{ + int err; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + err = sqlite3_clear_bindings(statement); + if (err != SQLITE_OK) { + throw_sqlite3_exception(env, GET_HANDLE(env, object)); + return; + } +} + +static void native_finalize(JNIEnv* env, jobject object) +{ + int err; + sqlite3_stmt * statement = GET_STATEMENT(env, object); + + if (statement != NULL) { + sqlite3_finalize(statement); + env->SetIntField(object, gStatementField, 0); + } +} + + +static JNINativeMethod sMethods[] = +{ + /* name, signature, funcPtr */ + {"native_compile", "(Ljava/lang/String;)V", (void *)native_compile}, + {"native_bind_null", "(I)V", (void *)native_bind_null}, + {"native_bind_long", "(IJ)V", (void *)native_bind_long}, + {"native_bind_double", "(ID)V", (void *)native_bind_double}, + {"native_bind_string", "(ILjava/lang/String;)V", (void *)native_bind_string}, + {"native_bind_blob", "(I[B)V", (void *)native_bind_blob}, + {"native_clear_bindings", "()V", (void *)native_clear_bindings}, + {"native_finalize", "()V", (void *)native_finalize}, +}; + +int register_android_database_SQLiteProgram(JNIEnv * env) +{ + jclass clazz; + + clazz = env->FindClass("android/database/sqlite/SQLiteProgram"); + if (clazz == NULL) { + LOGE("Can't find android/database/sqlite/SQLiteProgram"); + return -1; + } + + gHandleField = env->GetFieldID(clazz, "nHandle", "I"); + gStatementField = env->GetFieldID(clazz, "nStatement", "I"); + + if (gHandleField == NULL || gStatementField == NULL) { + LOGE("Error locating fields"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, + "android/database/sqlite/SQLiteProgram", sMethods, NELEM(sMethods)); +} + +} // namespace android |