1 /* 2 * Copyright (C) 2006-2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #undef LOG_TAG 18 #define LOG_TAG "Cursor" 19 20 #include <jni.h> 21 #include <JNIHelp.h> 22 #include <android_runtime/AndroidRuntime.h> 23 24 #include <sqlite3.h> 25 26 #include <utils/Log.h> 27 28 #include <stdio.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "sqlite3_exception.h" 33 34 35 namespace android { 36 37 static jfieldID gHandleField; 38 static jfieldID gStatementField; 39 40 41 #define GET_STATEMENT(env, object) \ 42 (sqlite3_stmt *)env->GetIntField(object, gStatementField) 43 #define GET_HANDLE(env, object) \ 44 (sqlite3 *)env->GetIntField(object, gHandleField) 45 46 47 sqlite3_stmt * compile(JNIEnv* env, jobject object, 48 sqlite3 * handle, jstring sqlString) 49 { 50 int err; 51 jchar const * sql; 52 jsize sqlLen; 53 sqlite3_stmt * statement = GET_STATEMENT(env, object); 54 55 // Make sure not to leak the statement if it already exists 56 if (statement != NULL) { 57 sqlite3_finalize(statement); 58 env->SetIntField(object, gStatementField, 0); 59 } 60 61 // Compile the SQL 62 sql = env->GetStringChars(sqlString, NULL); 63 sqlLen = env->GetStringLength(sqlString); 64 err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL); 65 env->ReleaseStringChars(sqlString, sql); 66 67 if (err == SQLITE_OK) { 68 // Store the statement in the Java object for future calls 69 LOGV("Prepared statement %p on %p", statement, handle); 70 env->SetIntField(object, gStatementField, (int)statement); 71 return statement; 72 } else { 73 // Error messages like 'near ")": syntax error' are not 74 // always helpful enough, so construct an error string that 75 // includes the query itself. 76 const char *query = env->GetStringUTFChars(sqlString, NULL); 77 char *message = (char*) malloc(strlen(query) + 50); 78 if (message) { 79 strcpy(message, ", while compiling: "); // less than 50 chars 80 strcat(message, query); 81 } 82 env->ReleaseStringUTFChars(sqlString, query); 83 throw_sqlite3_exception(env, handle, message); 84 free(message); 85 return NULL; 86 } 87 } 88 89 static void native_compile(JNIEnv* env, jobject object, jstring sqlString) 90 { 91 compile(env, object, GET_HANDLE(env, object), sqlString); 92 } 93 94 95 static JNINativeMethod sMethods[] = 96 { 97 /* name, signature, funcPtr */ 98 {"native_compile", "(Ljava/lang/String;)V", (void *)native_compile}, 99 }; 100 101 int register_android_database_SQLiteCompiledSql(JNIEnv * env) 102 { 103 jclass clazz; 104 105 clazz = env->FindClass("android/database/sqlite/SQLiteCompiledSql"); 106 if (clazz == NULL) { 107 LOGE("Can't find android/database/sqlite/SQLiteCompiledSql"); 108 return -1; 109 } 110 111 gHandleField = env->GetFieldID(clazz, "nHandle", "I"); 112 gStatementField = env->GetFieldID(clazz, "nStatement", "I"); 113 114 if (gHandleField == NULL || gStatementField == NULL) { 115 LOGE("Error locating fields"); 116 return -1; 117 } 118 119 return AndroidRuntime::registerNativeMethods(env, 120 "android/database/sqlite/SQLiteCompiledSql", sMethods, NELEM(sMethods)); 121 } 122 123 } // namespace android 124