1 /* //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 19 #define LOG_TAG "SQLiteStatementCpp" 20 21 #include "android_util_Binder.h" 22 23 #include <jni.h> 24 #include <JNIHelp.h> 25 #include <android_runtime/AndroidRuntime.h> 26 27 #include <sqlite3.h> 28 29 #include <cutils/ashmem.h> 30 #include <utils/Log.h> 31 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <sys/mman.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 40 #include "sqlite3_exception.h" 41 42 namespace android { 43 44 45 sqlite3_stmt * compile(JNIEnv* env, jobject object, 46 sqlite3 * handle, jstring sqlString); 47 48 static jfieldID gHandleField; 49 static 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 58 static jint native_execute(JNIEnv* env, jobject object) 59 { 60 int err; 61 sqlite3 * handle = GET_HANDLE(env, object); 62 sqlite3_stmt * statement = GET_STATEMENT(env, object); 63 int numChanges = -1; 64 65 // Execute the statement 66 err = sqlite3_step(statement); 67 68 // Throw an exception if an error occurred 69 if (err == SQLITE_ROW) { 70 throw_sqlite3_exception(env, 71 "Queries can be performed using SQLiteDatabase query or rawQuery methods only."); 72 } else if (err != SQLITE_DONE) { 73 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle)); 74 } else { 75 numChanges = sqlite3_changes(handle); 76 } 77 78 // Reset the statement so it's ready to use again 79 sqlite3_reset(statement); 80 return numChanges; 81 } 82 83 static 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 } 92 } 93 94 static 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 118 static 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 143 static jobject createParcelFileDescriptor(JNIEnv * env, int fd) 144 { 145 // Create FileDescriptor object 146 jobject fileDesc = jniCreateFileDescriptor(env, fd); 147 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. 166 static 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 212 static 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 242 static 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 253 static JNINativeMethod sMethods[] = 254 { 255 /* name, signature, funcPtr */ 256 {"native_execute", "()I", (void *)native_execute}, 257 {"native_executeInsert", "()J", (void *)native_executeInsert}, 258 {"native_1x1_long", "()J", (void *)native_1x1_long}, 259 {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string}, 260 {"native_1x1_blob_ashmem", "()Landroid/os/ParcelFileDescriptor;", (void *)native_1x1_blob_ashmem}, 261 {"native_executeSql", "(Ljava/lang/String;)V", (void *)native_executeSql}, 262 }; 263 264 int 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 287