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
native_bind_null(JNIEnv * env,jobject object,jint index)94 static void native_bind_null(JNIEnv* env, jobject object,
95 jint index)
96 {
97 int err;
98 sqlite3_stmt * statement = GET_STATEMENT(env, object);
99
100 err = sqlite3_bind_null(statement, index);
101 if (err != SQLITE_OK) {
102 char buf[32];
103 sprintf(buf, "handle %p", statement);
104 throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
105 return;
106 }
107 }
108
native_bind_long(JNIEnv * env,jobject object,jint index,jlong value)109 static void native_bind_long(JNIEnv* env, jobject object,
110 jint index, jlong value)
111 {
112 int err;
113 sqlite3_stmt * statement = GET_STATEMENT(env, object);
114
115 err = sqlite3_bind_int64(statement, index, value);
116 if (err != SQLITE_OK) {
117 char buf[32];
118 sprintf(buf, "handle %p", statement);
119 throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
120 return;
121 }
122 }
123
native_bind_double(JNIEnv * env,jobject object,jint index,jdouble value)124 static void native_bind_double(JNIEnv* env, jobject object,
125 jint index, jdouble value)
126 {
127 int err;
128 sqlite3_stmt * statement = GET_STATEMENT(env, object);
129
130 err = sqlite3_bind_double(statement, index, value);
131 if (err != SQLITE_OK) {
132 char buf[32];
133 sprintf(buf, "handle %p", statement);
134 throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
135 return;
136 }
137 }
138
native_bind_string(JNIEnv * env,jobject object,jint index,jstring sqlString)139 static void native_bind_string(JNIEnv* env, jobject object,
140 jint index, jstring sqlString)
141 {
142 int err;
143 jchar const * sql;
144 jsize sqlLen;
145 sqlite3_stmt * statement= GET_STATEMENT(env, object);
146
147 sql = env->GetStringChars(sqlString, NULL);
148 sqlLen = env->GetStringLength(sqlString);
149 err = sqlite3_bind_text16(statement, index, sql, sqlLen * 2, SQLITE_TRANSIENT);
150 env->ReleaseStringChars(sqlString, sql);
151 if (err != SQLITE_OK) {
152 char buf[32];
153 sprintf(buf, "handle %p", statement);
154 throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
155 return;
156 }
157 }
158
native_bind_blob(JNIEnv * env,jobject object,jint index,jbyteArray value)159 static void native_bind_blob(JNIEnv* env, jobject object,
160 jint index, jbyteArray value)
161 {
162 int err;
163 jchar const * sql;
164 jsize sqlLen;
165 sqlite3_stmt * statement= GET_STATEMENT(env, object);
166
167 jint len = env->GetArrayLength(value);
168 jbyte * bytes = env->GetByteArrayElements(value, NULL);
169
170 err = sqlite3_bind_blob(statement, index, bytes, len, SQLITE_TRANSIENT);
171 env->ReleaseByteArrayElements(value, bytes, JNI_ABORT);
172
173 if (err != SQLITE_OK) {
174 char buf[32];
175 sprintf(buf, "statement %p", statement);
176 throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
177 return;
178 }
179 }
180
native_clear_bindings(JNIEnv * env,jobject object)181 static void native_clear_bindings(JNIEnv* env, jobject object)
182 {
183 int err;
184 sqlite3_stmt * statement = GET_STATEMENT(env, object);
185
186 err = sqlite3_clear_bindings(statement);
187 if (err != SQLITE_OK) {
188 throw_sqlite3_exception(env, GET_HANDLE(env, object));
189 return;
190 }
191 }
192
native_finalize(JNIEnv * env,jobject object)193 static void native_finalize(JNIEnv* env, jobject object)
194 {
195 int err;
196 sqlite3_stmt * statement = GET_STATEMENT(env, object);
197
198 if (statement != NULL) {
199 sqlite3_finalize(statement);
200 env->SetIntField(object, gStatementField, 0);
201 }
202 }
203
204
205 static JNINativeMethod sMethods[] =
206 {
207 /* name, signature, funcPtr */
208 {"native_compile", "(Ljava/lang/String;)V", (void *)native_compile},
209 {"native_bind_null", "(I)V", (void *)native_bind_null},
210 {"native_bind_long", "(IJ)V", (void *)native_bind_long},
211 {"native_bind_double", "(ID)V", (void *)native_bind_double},
212 {"native_bind_string", "(ILjava/lang/String;)V", (void *)native_bind_string},
213 {"native_bind_blob", "(I[B)V", (void *)native_bind_blob},
214 {"native_clear_bindings", "()V", (void *)native_clear_bindings},
215 {"native_finalize", "()V", (void *)native_finalize},
216 };
217
register_android_database_SQLiteProgram(JNIEnv * env)218 int register_android_database_SQLiteProgram(JNIEnv * env)
219 {
220 jclass clazz;
221
222 clazz = env->FindClass("android/database/sqlite/SQLiteProgram");
223 if (clazz == NULL) {
224 LOGE("Can't find android/database/sqlite/SQLiteProgram");
225 return -1;
226 }
227
228 gHandleField = env->GetFieldID(clazz, "nHandle", "I");
229 gStatementField = env->GetFieldID(clazz, "nStatement", "I");
230
231 if (gHandleField == NULL || gStatementField == NULL) {
232 LOGE("Error locating fields");
233 return -1;
234 }
235
236 return AndroidRuntime::registerNativeMethods(env,
237 "android/database/sqlite/SQLiteProgram", sMethods, NELEM(sMethods));
238 }
239
240 } // namespace android
241