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
compile(JNIEnv * env,jobject object,sqlite3 * handle,jstring sqlString)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
native_compile(JNIEnv * env,jobject object,jstring sqlString)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
register_android_database_SQLiteCompiledSql(JNIEnv * env)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