blob: 05ffbb1d97afc1f5ba64b7300676c822c04454ff [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_database_SQLiteCursor.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#undef LOG_TAG
Vasu Norifb16cbd2010-07-25 16:38:48 -070019#define LOG_TAG "SQLiteStatementCpp"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
Bjorn Bringerta006b4722010-04-14 14:43:26 +010021#include "android_util_Binder.h"
22
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <jni.h>
24#include <JNIHelp.h>
25#include <android_runtime/AndroidRuntime.h>
26
27#include <sqlite3.h>
28
Bjorn Bringerta006b4722010-04-14 14:43:26 +010029#include <cutils/ashmem.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030#include <utils/Log.h>
31
Bjorn Bringerta006b4722010-04-14 14:43:26 +010032#include <fcntl.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033#include <stdio.h>
34#include <string.h>
35#include <unistd.h>
Bjorn Bringerta006b4722010-04-14 14:43:26 +010036#include <sys/mman.h>
37#include <sys/types.h>
38#include <sys/stat.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40#include "sqlite3_exception.h"
41
42namespace android {
43
44
45sqlite3_stmt * compile(JNIEnv* env, jobject object,
46 sqlite3 * handle, jstring sqlString);
47
48static jfieldID gHandleField;
49static jfieldID gStatementField;
50
51
52#define GET_STATEMENT(env, object) \
53 (sqlite3_stmt *)env->GetIntField(object, gStatementField)
54#define GET_HANDLE(env, object) \
55 (sqlite3 *)env->GetIntField(object, gHandleField)
56
57
Vasu Norifb16cbd2010-07-25 16:38:48 -070058static jint native_execute(JNIEnv* env, jobject object)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059{
60 int err;
61 sqlite3 * handle = GET_HANDLE(env, object);
62 sqlite3_stmt * statement = GET_STATEMENT(env, object);
Vasu Norifb16cbd2010-07-25 16:38:48 -070063 int numChanges = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65 // Execute the statement
66 err = sqlite3_step(statement);
67
Vasu Norifb16cbd2010-07-25 16:38:48 -070068 // Throw an exception if an error occurred
Vasu Norid72ec5f2010-05-25 15:21:18 -070069 if (err == SQLITE_ROW) {
Vasu Norifb16cbd2010-07-25 16:38:48 -070070 throw_sqlite3_exception(env,
71 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
Vasu Norid72ec5f2010-05-25 15:21:18 -070072 } else if (err != SQLITE_DONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
Vasu Norifb16cbd2010-07-25 16:38:48 -070074 } else {
75 numChanges = sqlite3_changes(handle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 }
77
Vasu Norifb16cbd2010-07-25 16:38:48 -070078 // Reset the statement so it's ready to use again
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 sqlite3_reset(statement);
Vasu Norifb16cbd2010-07-25 16:38:48 -070080 return numChanges;
81}
82
83static jlong native_executeInsert(JNIEnv* env, jobject object)
84{
85 sqlite3 * handle = GET_HANDLE(env, object);
86 jint numChanges = native_execute(env, object);
87 if (numChanges > 0) {
88 return sqlite3_last_insert_rowid(handle);
89 } else {
90 return -1;
91 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092}
93
94static jlong native_1x1_long(JNIEnv* env, jobject object)
95{
96 int err;
97 sqlite3 * handle = GET_HANDLE(env, object);
98 sqlite3_stmt * statement = GET_STATEMENT(env, object);
99 jlong value = -1;
100
101 // Execute the statement
102 err = sqlite3_step(statement);
103
104 // Handle the result
105 if (err == SQLITE_ROW) {
106 // No errors, read the data and return it
107 value = sqlite3_column_int64(statement, 0);
108 } else {
109 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
110 }
111
112 // Reset the statment so it's ready to use again
113 sqlite3_reset(statement);
114
115 return value;
116}
117
118static jstring native_1x1_string(JNIEnv* env, jobject object)
119{
120 int err;
121 sqlite3 * handle = GET_HANDLE(env, object);
122 sqlite3_stmt * statement = GET_STATEMENT(env, object);
123 jstring value = NULL;
124
125 // Execute the statement
126 err = sqlite3_step(statement);
127
128 // Handle the result
129 if (err == SQLITE_ROW) {
130 // No errors, read the data and return it
131 char const * text = (char const *)sqlite3_column_text(statement, 0);
132 value = env->NewStringUTF(text);
133 } else {
134 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
135 }
136
137 // Reset the statment so it's ready to use again
138 sqlite3_reset(statement);
139
140 return value;
141}
142
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100143static jobject createParcelFileDescriptor(JNIEnv * env, int fd)
144{
145 // Create FileDescriptor object
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700146 jobject fileDesc = jniCreateFileDescriptor(env, fd);
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100147 if (fileDesc == NULL) {
148 // FileDescriptor constructor has thrown an exception
149 close(fd);
150 return NULL;
151 }
152
153 // Wrap it in a ParcelFileDescriptor
154 jobject parcelFileDesc = newParcelFileDescriptor(env, fileDesc);
155 if (parcelFileDesc == NULL) {
156 // ParcelFileDescriptor constructor has thrown an exception
157 close(fd);
158 return NULL;
159 }
160
161 return parcelFileDesc;
162}
163
164// Creates an ashmem area, copies some data into it, and returns
165// a ParcelFileDescriptor for the ashmem area.
166static jobject create_ashmem_region_with_data(JNIEnv * env,
167 const void * data, int length)
168{
169 // Create ashmem area
170 int fd = ashmem_create_region(NULL, length);
171 if (fd < 0) {
172 LOGE("ashmem_create_region failed: %s", strerror(errno));
173 jniThrowIOException(env, errno);
174 return NULL;
175 }
176
177 if (length > 0) {
178 // mmap the ashmem area
179 void * ashmem_ptr =
180 mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
181 if (ashmem_ptr == MAP_FAILED) {
182 LOGE("mmap failed: %s", strerror(errno));
183 jniThrowIOException(env, errno);
184 close(fd);
185 return NULL;
186 }
187
188 // Copy data to ashmem area
189 memcpy(ashmem_ptr, data, length);
190
191 // munmap ashmem area
192 if (munmap(ashmem_ptr, length) < 0) {
193 LOGE("munmap failed: %s", strerror(errno));
194 jniThrowIOException(env, errno);
195 close(fd);
196 return NULL;
197 }
198 }
199
200 // Make ashmem area read-only
201 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
202 LOGE("ashmem_set_prot_region failed: %s", strerror(errno));
203 jniThrowIOException(env, errno);
204 close(fd);
205 return NULL;
206 }
207
208 // Wrap it in a ParcelFileDescriptor
209 return createParcelFileDescriptor(env, fd);
210}
211
212static jobject native_1x1_blob_ashmem(JNIEnv* env, jobject object)
213{
214 int err;
215 sqlite3 * handle = GET_HANDLE(env, object);
216 sqlite3_stmt * statement = GET_STATEMENT(env, object);
217 jobject value = NULL;
218
219 // Execute the statement
220 err = sqlite3_step(statement);
221
222 // Handle the result
223 if (err == SQLITE_ROW) {
224 // No errors, read the data and return it
225 const void * blob = sqlite3_column_blob(statement, 0);
226 if (blob != NULL) {
227 int len = sqlite3_column_bytes(statement, 0);
228 if (len >= 0) {
229 value = create_ashmem_region_with_data(env, blob, len);
230 }
231 }
232 } else {
233 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle));
234 }
235
236 // Reset the statment so it's ready to use again
237 sqlite3_reset(statement);
238
239 return value;
240}
241
Vasu Nori4e874ed2010-09-15 18:40:49 -0700242static void native_executeSql(JNIEnv* env, jobject object, jstring sql)
243{
244 char const* sqlString = env->GetStringUTFChars(sql, NULL);
245 sqlite3 * handle = GET_HANDLE(env, object);
246 int err = sqlite3_exec(handle, sqlString, NULL, NULL, NULL);
247 if (err != SQLITE_OK) {
248 throw_sqlite3_exception(env, handle);
249 }
250 env->ReleaseStringUTFChars(sql, sqlString);
251}
252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253static JNINativeMethod sMethods[] =
254{
255 /* name, signature, funcPtr */
Vasu Norifb16cbd2010-07-25 16:38:48 -0700256 {"native_execute", "()I", (void *)native_execute},
257 {"native_executeInsert", "()J", (void *)native_executeInsert},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 {"native_1x1_long", "()J", (void *)native_1x1_long},
259 {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string},
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100260 {"native_1x1_blob_ashmem", "()Landroid/os/ParcelFileDescriptor;", (void *)native_1x1_blob_ashmem},
Vasu Nori4e874ed2010-09-15 18:40:49 -0700261 {"native_executeSql", "(Ljava/lang/String;)V", (void *)native_executeSql},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262};
263
264int register_android_database_SQLiteStatement(JNIEnv * env)
265{
266 jclass clazz;
267
268 clazz = env->FindClass("android/database/sqlite/SQLiteStatement");
269 if (clazz == NULL) {
270 LOGE("Can't find android/database/sqlite/SQLiteStatement");
271 return -1;
272 }
273
274 gHandleField = env->GetFieldID(clazz, "nHandle", "I");
275 gStatementField = env->GetFieldID(clazz, "nStatement", "I");
276
277 if (gHandleField == NULL || gStatementField == NULL) {
278 LOGE("Error locating fields");
279 return -1;
280 }
281
282 return AndroidRuntime::registerNativeMethods(env,
283 "android/database/sqlite/SQLiteStatement", sMethods, NELEM(sMethods));
284}
285
286} // namespace android