• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 #define LOG_TAG "SQLiteConnection"
18 
19 #include <jni.h>
20 #include <nativehelper/JNIHelp.h>
21 #include <android_runtime/AndroidRuntime.h>
22 #include <android_runtime/Log.h>
23 
24 #include <utils/Log.h>
25 #include <utils/String8.h>
26 #include <utils/String16.h>
27 #include <cutils/ashmem.h>
28 #include <sys/mman.h>
29 
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include <androidfw/CursorWindow.h>
34 
35 #include <sqlite3.h>
36 #include <sqlite3_android.h>
37 
38 #include "android_database_SQLiteCommon.h"
39 
40 #include "core_jni_helpers.h"
41 
42 // Set to 1 to use UTF16 storage for localized indexes.
43 #define UTF16_STORAGE 0
44 
45 namespace android {
46 
47 /* Busy timeout in milliseconds.
48  * If another connection (possibly in another process) has the database locked for
49  * longer than this amount of time then SQLite will generate a SQLITE_BUSY error.
50  * The SQLITE_BUSY error is then raised as a SQLiteDatabaseLockedException.
51  *
52  * In ordinary usage, busy timeouts are quite rare.  Most databases only ever
53  * have a single open connection at a time unless they are using WAL.  When using
54  * WAL, a timeout could occur if one connection is busy performing an auto-checkpoint
55  * operation.  The busy timeout needs to be long enough to tolerate slow I/O write
56  * operations but not so long as to cause the application to hang indefinitely if
57  * there is a problem acquiring a database lock.
58  */
59 static const int BUSY_TIMEOUT_MS = 2500;
60 
61 static struct {
62     jfieldID name;
63     jfieldID numArgs;
64     jmethodID dispatchCallback;
65 } gSQLiteCustomFunctionClassInfo;
66 
67 static struct {
68     jclass clazz;
69 } gStringClassInfo;
70 
71 struct SQLiteConnection {
72     // Open flags.
73     // Must be kept in sync with the constants defined in SQLiteDatabase.java.
74     enum {
75         OPEN_READWRITE          = 0x00000000,
76         OPEN_READONLY           = 0x00000001,
77         OPEN_READ_MASK          = 0x00000001,
78         NO_LOCALIZED_COLLATORS  = 0x00000010,
79         CREATE_IF_NECESSARY     = 0x10000000,
80     };
81 
82     sqlite3* const db;
83     const int openFlags;
84     const String8 path;
85     const String8 label;
86 
87     volatile bool canceled;
88 
SQLiteConnectionandroid::SQLiteConnection89     SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
90         db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
91 };
92 
93 // Called each time a statement begins execution, when tracing is enabled.
sqliteTraceCallback(void * data,const char * sql)94 static void sqliteTraceCallback(void *data, const char *sql) {
95     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
96     ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n",
97             connection->label.string(), sql);
98 }
99 
100 // Called each time a statement finishes execution, when profiling is enabled.
sqliteProfileCallback(void * data,const char * sql,sqlite3_uint64 tm)101 static void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) {
102     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
103     ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n",
104             connection->label.string(), sql, tm * 0.000001f);
105 }
106 
107 // Called after each SQLite VM instruction when cancelation is enabled.
sqliteProgressHandlerCallback(void * data)108 static int sqliteProgressHandlerCallback(void* data) {
109     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
110     return connection->canceled;
111 }
112 
113 
nativeOpen(JNIEnv * env,jclass clazz,jstring pathStr,jint openFlags,jstring labelStr,jboolean enableTrace,jboolean enableProfile,jint lookasideSz,jint lookasideCnt)114 static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
115         jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
116         jint lookasideCnt) {
117     int sqliteFlags;
118     if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
119         sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
120     } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
121         sqliteFlags = SQLITE_OPEN_READONLY;
122     } else {
123         sqliteFlags = SQLITE_OPEN_READWRITE;
124     }
125 
126     const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
127     String8 path(pathChars);
128     env->ReleaseStringUTFChars(pathStr, pathChars);
129 
130     const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
131     String8 label(labelChars);
132     env->ReleaseStringUTFChars(labelStr, labelChars);
133 
134     sqlite3* db;
135     int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
136     if (err != SQLITE_OK) {
137         throw_sqlite3_exception_errcode(env, err, "Could not open database");
138         return 0;
139     }
140 
141     if (lookasideSz >= 0 && lookasideCnt >= 0) {
142         int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
143         if (err != SQLITE_OK) {
144             ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
145             throw_sqlite3_exception(env, db, "Cannot set lookaside");
146             sqlite3_close(db);
147             return 0;
148         }
149     }
150 
151     // Check that the database is really read/write when that is what we asked for.
152     if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
153         throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
154         sqlite3_close(db);
155         return 0;
156     }
157 
158     // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
159     err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
160     if (err != SQLITE_OK) {
161         throw_sqlite3_exception(env, db, "Could not set busy timeout");
162         sqlite3_close(db);
163         return 0;
164     }
165 
166     // Register custom Android functions.
167     err = register_android_functions(db, UTF16_STORAGE);
168     if (err) {
169         throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
170         sqlite3_close(db);
171         return 0;
172     }
173 
174     // Create wrapper object.
175     SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);
176 
177     // Enable tracing and profiling if requested.
178     if (enableTrace) {
179         sqlite3_trace(db, &sqliteTraceCallback, connection);
180     }
181     if (enableProfile) {
182         sqlite3_profile(db, &sqliteProfileCallback, connection);
183     }
184 
185     ALOGV("Opened connection %p with label '%s'", db, label.string());
186     return reinterpret_cast<jlong>(connection);
187 }
188 
nativeClose(JNIEnv * env,jclass clazz,jlong connectionPtr)189 static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
190     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
191 
192     if (connection) {
193         ALOGV("Closing connection %p", connection->db);
194         int err = sqlite3_close(connection->db);
195         if (err != SQLITE_OK) {
196             // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
197             ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
198             throw_sqlite3_exception(env, connection->db, "Count not close db.");
199             return;
200         }
201 
202         delete connection;
203     }
204 }
205 
206 // Called each time a custom function is evaluated.
sqliteCustomFunctionCallback(sqlite3_context * context,int argc,sqlite3_value ** argv)207 static void sqliteCustomFunctionCallback(sqlite3_context *context,
208         int argc, sqlite3_value **argv) {
209     JNIEnv* env = AndroidRuntime::getJNIEnv();
210 
211     // Get the callback function object.
212     // Create a new local reference to it in case the callback tries to do something
213     // dumb like unregister the function (thereby destroying the global ref) while it is running.
214     jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context));
215     jobject functionObj = env->NewLocalRef(functionObjGlobal);
216 
217     jobjectArray argsArray = env->NewObjectArray(argc, gStringClassInfo.clazz, NULL);
218     if (argsArray) {
219         for (int i = 0; i < argc; i++) {
220             const jchar* arg = static_cast<const jchar*>(sqlite3_value_text16(argv[i]));
221             if (!arg) {
222                 ALOGW("NULL argument in custom_function_callback.  This should not happen.");
223             } else {
224                 size_t argLen = sqlite3_value_bytes16(argv[i]) / sizeof(jchar);
225                 jstring argStr = env->NewString(arg, argLen);
226                 if (!argStr) {
227                     goto error; // out of memory error
228                 }
229                 env->SetObjectArrayElement(argsArray, i, argStr);
230                 env->DeleteLocalRef(argStr);
231             }
232         }
233 
234         // TODO: Support functions that return values.
235         env->CallVoidMethod(functionObj,
236                 gSQLiteCustomFunctionClassInfo.dispatchCallback, argsArray);
237 
238 error:
239         env->DeleteLocalRef(argsArray);
240     }
241 
242     env->DeleteLocalRef(functionObj);
243 
244     if (env->ExceptionCheck()) {
245         ALOGE("An exception was thrown by custom SQLite function.");
246         LOGE_EX(env);
247         env->ExceptionClear();
248     }
249 }
250 
251 // Called when a custom function is destroyed.
sqliteCustomFunctionDestructor(void * data)252 static void sqliteCustomFunctionDestructor(void* data) {
253     jobject functionObjGlobal = reinterpret_cast<jobject>(data);
254 
255     JNIEnv* env = AndroidRuntime::getJNIEnv();
256     env->DeleteGlobalRef(functionObjGlobal);
257 }
258 
nativeRegisterCustomFunction(JNIEnv * env,jclass clazz,jlong connectionPtr,jobject functionObj)259 static void nativeRegisterCustomFunction(JNIEnv* env, jclass clazz, jlong connectionPtr,
260         jobject functionObj) {
261     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
262 
263     jstring nameStr = jstring(env->GetObjectField(
264             functionObj, gSQLiteCustomFunctionClassInfo.name));
265     jint numArgs = env->GetIntField(functionObj, gSQLiteCustomFunctionClassInfo.numArgs);
266 
267     jobject functionObjGlobal = env->NewGlobalRef(functionObj);
268 
269     const char* name = env->GetStringUTFChars(nameStr, NULL);
270     int err = sqlite3_create_function_v2(connection->db, name, numArgs, SQLITE_UTF16,
271             reinterpret_cast<void*>(functionObjGlobal),
272             &sqliteCustomFunctionCallback, NULL, NULL, &sqliteCustomFunctionDestructor);
273     env->ReleaseStringUTFChars(nameStr, name);
274 
275     if (err != SQLITE_OK) {
276         ALOGE("sqlite3_create_function returned %d", err);
277         env->DeleteGlobalRef(functionObjGlobal);
278         throw_sqlite3_exception(env, connection->db);
279         return;
280     }
281 }
282 
nativeRegisterLocalizedCollators(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring localeStr)283 static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jlong connectionPtr,
284         jstring localeStr) {
285     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
286 
287     const char* locale = env->GetStringUTFChars(localeStr, NULL);
288     int err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
289     env->ReleaseStringUTFChars(localeStr, locale);
290 
291     if (err != SQLITE_OK) {
292         throw_sqlite3_exception(env, connection->db);
293     }
294 }
295 
nativePrepareStatement(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring sqlString)296 static jlong nativePrepareStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
297         jstring sqlString) {
298     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
299 
300     jsize sqlLength = env->GetStringLength(sqlString);
301     const jchar* sql = env->GetStringCritical(sqlString, NULL);
302     sqlite3_stmt* statement;
303     int err = sqlite3_prepare16_v2(connection->db,
304             sql, sqlLength * sizeof(jchar), &statement, NULL);
305     env->ReleaseStringCritical(sqlString, sql);
306 
307     if (err != SQLITE_OK) {
308         // Error messages like 'near ")": syntax error' are not
309         // always helpful enough, so construct an error string that
310         // includes the query itself.
311         const char *query = env->GetStringUTFChars(sqlString, NULL);
312         char *message = (char*) malloc(strlen(query) + 50);
313         if (message) {
314             strcpy(message, ", while compiling: "); // less than 50 chars
315             strcat(message, query);
316         }
317         env->ReleaseStringUTFChars(sqlString, query);
318         throw_sqlite3_exception(env, connection->db, message);
319         free(message);
320         return 0;
321     }
322 
323     ALOGV("Prepared statement %p on connection %p", statement, connection->db);
324     return reinterpret_cast<jlong>(statement);
325 }
326 
nativeFinalizeStatement(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)327 static void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
328         jlong statementPtr) {
329     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
330     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
331 
332     // We ignore the result of sqlite3_finalize because it is really telling us about
333     // whether any errors occurred while executing the statement.  The statement itself
334     // is always finalized regardless.
335     ALOGV("Finalized statement %p on connection %p", statement, connection->db);
336     sqlite3_finalize(statement);
337 }
338 
nativeGetParameterCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)339 static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
340         jlong statementPtr) {
341     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
342 
343     return sqlite3_bind_parameter_count(statement);
344 }
345 
nativeIsReadOnly(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)346 static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jlong connectionPtr,
347         jlong statementPtr) {
348     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
349 
350     return sqlite3_stmt_readonly(statement) != 0;
351 }
352 
nativeGetColumnCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)353 static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
354         jlong statementPtr) {
355     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
356 
357     return sqlite3_column_count(statement);
358 }
359 
nativeGetColumnName(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index)360 static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jlong connectionPtr,
361         jlong statementPtr, jint index) {
362     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
363 
364     const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index));
365     if (name) {
366         size_t length = 0;
367         while (name[length]) {
368             length += 1;
369         }
370         return env->NewString(name, length);
371     }
372     return NULL;
373 }
374 
nativeBindNull(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index)375 static void nativeBindNull(JNIEnv* env, jclass clazz, jlong connectionPtr,
376         jlong statementPtr, jint index) {
377     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
378     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
379 
380     int err = sqlite3_bind_null(statement, index);
381     if (err != SQLITE_OK) {
382         throw_sqlite3_exception(env, connection->db, NULL);
383     }
384 }
385 
nativeBindLong(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jlong value)386 static void nativeBindLong(JNIEnv* env, jclass clazz, jlong connectionPtr,
387         jlong statementPtr, jint index, jlong value) {
388     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
389     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
390 
391     int err = sqlite3_bind_int64(statement, index, value);
392     if (err != SQLITE_OK) {
393         throw_sqlite3_exception(env, connection->db, NULL);
394     }
395 }
396 
nativeBindDouble(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jdouble value)397 static void nativeBindDouble(JNIEnv* env, jclass clazz, jlong connectionPtr,
398         jlong statementPtr, jint index, jdouble value) {
399     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
400     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
401 
402     int err = sqlite3_bind_double(statement, index, value);
403     if (err != SQLITE_OK) {
404         throw_sqlite3_exception(env, connection->db, NULL);
405     }
406 }
407 
nativeBindString(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jstring valueString)408 static void nativeBindString(JNIEnv* env, jclass clazz, jlong connectionPtr,
409         jlong statementPtr, jint index, jstring valueString) {
410     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
411     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
412 
413     jsize valueLength = env->GetStringLength(valueString);
414     const jchar* value = env->GetStringCritical(valueString, NULL);
415     int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar),
416             SQLITE_TRANSIENT);
417     env->ReleaseStringCritical(valueString, value);
418     if (err != SQLITE_OK) {
419         throw_sqlite3_exception(env, connection->db, NULL);
420     }
421 }
422 
nativeBindBlob(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jbyteArray valueArray)423 static void nativeBindBlob(JNIEnv* env, jclass clazz, jlong connectionPtr,
424         jlong statementPtr, jint index, jbyteArray valueArray) {
425     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
426     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
427 
428     jsize valueLength = env->GetArrayLength(valueArray);
429     jbyte* value = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(valueArray, NULL));
430     int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT);
431     env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT);
432     if (err != SQLITE_OK) {
433         throw_sqlite3_exception(env, connection->db, NULL);
434     }
435 }
436 
nativeResetStatementAndClearBindings(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)437 static void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jlong connectionPtr,
438         jlong statementPtr) {
439     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
440     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
441 
442     int err = sqlite3_reset(statement);
443     if (err == SQLITE_OK) {
444         err = sqlite3_clear_bindings(statement);
445     }
446     if (err != SQLITE_OK) {
447         throw_sqlite3_exception(env, connection->db, NULL);
448     }
449 }
450 
executeNonQuery(JNIEnv * env,SQLiteConnection * connection,sqlite3_stmt * statement)451 static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
452     int err = sqlite3_step(statement);
453     if (err == SQLITE_ROW) {
454         throw_sqlite3_exception(env,
455                 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
456     } else if (err != SQLITE_DONE) {
457         throw_sqlite3_exception(env, connection->db);
458     }
459     return err;
460 }
461 
nativeExecute(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)462 static void nativeExecute(JNIEnv* env, jclass clazz, jlong connectionPtr,
463         jlong statementPtr) {
464     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
465     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
466 
467     executeNonQuery(env, connection, statement);
468 }
469 
nativeExecuteForChangedRowCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)470 static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
471         jlong connectionPtr, jlong statementPtr) {
472     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
473     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
474 
475     int err = executeNonQuery(env, connection, statement);
476     return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1;
477 }
478 
nativeExecuteForLastInsertedRowId(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)479 static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
480         jlong connectionPtr, jlong statementPtr) {
481     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
482     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
483 
484     int err = executeNonQuery(env, connection, statement);
485     return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0
486             ? sqlite3_last_insert_rowid(connection->db) : -1;
487 }
488 
executeOneRowQuery(JNIEnv * env,SQLiteConnection * connection,sqlite3_stmt * statement)489 static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
490     int err = sqlite3_step(statement);
491     if (err != SQLITE_ROW) {
492         throw_sqlite3_exception(env, connection->db);
493     }
494     return err;
495 }
496 
nativeExecuteForLong(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)497 static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
498         jlong connectionPtr, jlong statementPtr) {
499     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
500     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
501 
502     int err = executeOneRowQuery(env, connection, statement);
503     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
504         return sqlite3_column_int64(statement, 0);
505     }
506     return -1;
507 }
508 
nativeExecuteForString(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)509 static jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
510         jlong connectionPtr, jlong statementPtr) {
511     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
512     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
513 
514     int err = executeOneRowQuery(env, connection, statement);
515     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
516         const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0));
517         if (text) {
518             size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar);
519             return env->NewString(text, length);
520         }
521     }
522     return NULL;
523 }
524 
createAshmemRegionWithData(JNIEnv * env,const void * data,size_t length)525 static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
526     int error = 0;
527     int fd = ashmem_create_region(NULL, length);
528     if (fd < 0) {
529         error = errno;
530         ALOGE("ashmem_create_region failed: %s", strerror(error));
531     } else {
532         if (length > 0) {
533             void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
534             if (ptr == MAP_FAILED) {
535                 error = errno;
536                 ALOGE("mmap failed: %s", strerror(error));
537             } else {
538                 memcpy(ptr, data, length);
539                 munmap(ptr, length);
540             }
541         }
542 
543         if (!error) {
544             if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
545                 error = errno;
546                 ALOGE("ashmem_set_prot_region failed: %s", strerror(errno));
547             } else {
548                 return fd;
549             }
550         }
551 
552         close(fd);
553     }
554 
555     jniThrowIOException(env, error);
556     return -1;
557 }
558 
nativeExecuteForBlobFileDescriptor(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)559 static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
560         jlong connectionPtr, jlong statementPtr) {
561     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
562     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
563 
564     int err = executeOneRowQuery(env, connection, statement);
565     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
566         const void* blob = sqlite3_column_blob(statement, 0);
567         if (blob) {
568             int length = sqlite3_column_bytes(statement, 0);
569             if (length >= 0) {
570                 return createAshmemRegionWithData(env, blob, length);
571             }
572         }
573     }
574     return -1;
575 }
576 
577 enum CopyRowResult {
578     CPR_OK,
579     CPR_FULL,
580     CPR_ERROR,
581 };
582 
copyRow(JNIEnv * env,CursorWindow * window,sqlite3_stmt * statement,int numColumns,int startPos,int addedRows)583 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
584         sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
585     // Allocate a new field directory for the row.
586     status_t status = window->allocRow();
587     if (status) {
588         LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
589                 startPos, addedRows, status);
590         return CPR_FULL;
591     }
592 
593     // Pack the row into the window.
594     CopyRowResult result = CPR_OK;
595     for (int i = 0; i < numColumns; i++) {
596         int type = sqlite3_column_type(statement, i);
597         if (type == SQLITE_TEXT) {
598             // TEXT data
599             const char* text = reinterpret_cast<const char*>(
600                     sqlite3_column_text(statement, i));
601             // SQLite does not include the NULL terminator in size, but does
602             // ensure all strings are NULL terminated, so increase size by
603             // one to make sure we store the terminator.
604             size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
605             status = window->putString(addedRows, i, text, sizeIncludingNull);
606             if (status) {
607                 LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
608                         sizeIncludingNull, startPos + addedRows, i, status);
609                 result = CPR_FULL;
610                 break;
611             }
612             LOG_WINDOW("%d,%d is TEXT with %u bytes",
613                     startPos + addedRows, i, sizeIncludingNull);
614         } else if (type == SQLITE_INTEGER) {
615             // INTEGER data
616             int64_t value = sqlite3_column_int64(statement, i);
617             status = window->putLong(addedRows, i, value);
618             if (status) {
619                 LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
620                         i, status);
621                 result = CPR_FULL;
622                 break;
623             }
624             LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
625         } else if (type == SQLITE_FLOAT) {
626             // FLOAT data
627             double value = sqlite3_column_double(statement, i);
628             status = window->putDouble(addedRows, i, value);
629             if (status) {
630                 LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
631                         i, status);
632                 result = CPR_FULL;
633                 break;
634             }
635             LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
636         } else if (type == SQLITE_BLOB) {
637             // BLOB data
638             const void* blob = sqlite3_column_blob(statement, i);
639             size_t size = sqlite3_column_bytes(statement, i);
640             status = window->putBlob(addedRows, i, blob, size);
641             if (status) {
642                 LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
643                         size, startPos + addedRows, i, status);
644                 result = CPR_FULL;
645                 break;
646             }
647             LOG_WINDOW("%d,%d is Blob with %u bytes",
648                     startPos + addedRows, i, size);
649         } else if (type == SQLITE_NULL) {
650             // NULL field
651             status = window->putNull(addedRows, i);
652             if (status) {
653                 LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
654                         i, status);
655                 result = CPR_FULL;
656                 break;
657             }
658 
659             LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
660         } else {
661             // Unknown data
662             ALOGE("Unknown column type when filling database window");
663             throw_sqlite3_exception(env, "Unknown column type when filling window");
664             result = CPR_ERROR;
665             break;
666         }
667     }
668 
669     // Free the last row if if was not successfully copied.
670     if (result != CPR_OK) {
671         window->freeLastRow();
672     }
673     return result;
674 }
675 
nativeExecuteForCursorWindow(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jlong windowPtr,jint startPos,jint requiredPos,jboolean countAllRows)676 static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
677         jlong connectionPtr, jlong statementPtr, jlong windowPtr,
678         jint startPos, jint requiredPos, jboolean countAllRows) {
679     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
680     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
681     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
682 
683     status_t status = window->clear();
684     if (status) {
685         String8 msg;
686         msg.appendFormat("Failed to clear the cursor window, status=%d", status);
687         throw_sqlite3_exception(env, connection->db, msg.string());
688         return 0;
689     }
690 
691     int numColumns = sqlite3_column_count(statement);
692     status = window->setNumColumns(numColumns);
693     if (status) {
694         String8 msg;
695         msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
696                 numColumns, status);
697         throw_sqlite3_exception(env, connection->db, msg.string());
698         return 0;
699     }
700 
701     int retryCount = 0;
702     int totalRows = 0;
703     int addedRows = 0;
704     bool windowFull = false;
705     bool gotException = false;
706     while (!gotException && (!windowFull || countAllRows)) {
707         int err = sqlite3_step(statement);
708         if (err == SQLITE_ROW) {
709             LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
710             retryCount = 0;
711             totalRows += 1;
712 
713             // Skip the row if the window is full or we haven't reached the start position yet.
714             if (startPos >= totalRows || windowFull) {
715                 continue;
716             }
717 
718             CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
719             if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
720                 // We filled the window before we got to the one row that we really wanted.
721                 // Clear the window and start filling it again from here.
722                 // TODO: Would be nicer if we could progressively replace earlier rows.
723                 window->clear();
724                 window->setNumColumns(numColumns);
725                 startPos += addedRows;
726                 addedRows = 0;
727                 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
728             }
729 
730             if (cpr == CPR_OK) {
731                 addedRows += 1;
732             } else if (cpr == CPR_FULL) {
733                 windowFull = true;
734             } else {
735                 gotException = true;
736             }
737         } else if (err == SQLITE_DONE) {
738             // All rows processed, bail
739             LOG_WINDOW("Processed all rows");
740             break;
741         } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
742             // The table is locked, retry
743             LOG_WINDOW("Database locked, retrying");
744             if (retryCount > 50) {
745                 ALOGE("Bailing on database busy retry");
746                 throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
747                 gotException = true;
748             } else {
749                 // Sleep to give the thread holding the lock a chance to finish
750                 usleep(1000);
751                 retryCount++;
752             }
753         } else {
754             throw_sqlite3_exception(env, connection->db);
755             gotException = true;
756         }
757     }
758 
759     LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
760             "to the window in %d bytes",
761             statement, totalRows, addedRows, window->size() - window->freeSpace());
762     sqlite3_reset(statement);
763 
764     // Report the total number of rows on request.
765     if (startPos > totalRows) {
766         ALOGE("startPos %d > actual rows %d", startPos, totalRows);
767     }
768     jlong result = jlong(startPos) << 32 | jlong(totalRows);
769     return result;
770 }
771 
nativeGetDbLookaside(JNIEnv * env,jobject clazz,jlong connectionPtr)772 static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jlong connectionPtr) {
773     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
774 
775     int cur = -1;
776     int unused;
777     sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0);
778     return cur;
779 }
780 
nativeCancel(JNIEnv * env,jobject clazz,jlong connectionPtr)781 static void nativeCancel(JNIEnv* env, jobject clazz, jlong connectionPtr) {
782     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
783     connection->canceled = true;
784 }
785 
nativeResetCancel(JNIEnv * env,jobject clazz,jlong connectionPtr,jboolean cancelable)786 static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
787         jboolean cancelable) {
788     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
789     connection->canceled = false;
790 
791     if (cancelable) {
792         sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
793                 connection);
794     } else {
795         sqlite3_progress_handler(connection->db, 0, NULL, NULL);
796     }
797 }
798 
799 
800 static const JNINativeMethod sMethods[] =
801 {
802     /* name, signature, funcPtr */
803     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
804             (void*)nativeOpen },
805     { "nativeClose", "(J)V",
806             (void*)nativeClose },
807     { "nativeRegisterCustomFunction", "(JLandroid/database/sqlite/SQLiteCustomFunction;)V",
808             (void*)nativeRegisterCustomFunction },
809     { "nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
810             (void*)nativeRegisterLocalizedCollators },
811     { "nativePrepareStatement", "(JLjava/lang/String;)J",
812             (void*)nativePrepareStatement },
813     { "nativeFinalizeStatement", "(JJ)V",
814             (void*)nativeFinalizeStatement },
815     { "nativeGetParameterCount", "(JJ)I",
816             (void*)nativeGetParameterCount },
817     { "nativeIsReadOnly", "(JJ)Z",
818             (void*)nativeIsReadOnly },
819     { "nativeGetColumnCount", "(JJ)I",
820             (void*)nativeGetColumnCount },
821     { "nativeGetColumnName", "(JJI)Ljava/lang/String;",
822             (void*)nativeGetColumnName },
823     { "nativeBindNull", "(JJI)V",
824             (void*)nativeBindNull },
825     { "nativeBindLong", "(JJIJ)V",
826             (void*)nativeBindLong },
827     { "nativeBindDouble", "(JJID)V",
828             (void*)nativeBindDouble },
829     { "nativeBindString", "(JJILjava/lang/String;)V",
830             (void*)nativeBindString },
831     { "nativeBindBlob", "(JJI[B)V",
832             (void*)nativeBindBlob },
833     { "nativeResetStatementAndClearBindings", "(JJ)V",
834             (void*)nativeResetStatementAndClearBindings },
835     { "nativeExecute", "(JJ)V",
836             (void*)nativeExecute },
837     { "nativeExecuteForLong", "(JJ)J",
838             (void*)nativeExecuteForLong },
839     { "nativeExecuteForString", "(JJ)Ljava/lang/String;",
840             (void*)nativeExecuteForString },
841     { "nativeExecuteForBlobFileDescriptor", "(JJ)I",
842             (void*)nativeExecuteForBlobFileDescriptor },
843     { "nativeExecuteForChangedRowCount", "(JJ)I",
844             (void*)nativeExecuteForChangedRowCount },
845     { "nativeExecuteForLastInsertedRowId", "(JJ)J",
846             (void*)nativeExecuteForLastInsertedRowId },
847     { "nativeExecuteForCursorWindow", "(JJJIIZ)J",
848             (void*)nativeExecuteForCursorWindow },
849     { "nativeGetDbLookaside", "(J)I",
850             (void*)nativeGetDbLookaside },
851     { "nativeCancel", "(J)V",
852             (void*)nativeCancel },
853     { "nativeResetCancel", "(JZ)V",
854             (void*)nativeResetCancel },
855 };
856 
register_android_database_SQLiteConnection(JNIEnv * env)857 int register_android_database_SQLiteConnection(JNIEnv *env)
858 {
859     jclass clazz = FindClassOrDie(env, "android/database/sqlite/SQLiteCustomFunction");
860 
861     gSQLiteCustomFunctionClassInfo.name = GetFieldIDOrDie(env, clazz, "name", "Ljava/lang/String;");
862     gSQLiteCustomFunctionClassInfo.numArgs = GetFieldIDOrDie(env, clazz, "numArgs", "I");
863     gSQLiteCustomFunctionClassInfo.dispatchCallback = GetMethodIDOrDie(env, clazz,
864             "dispatchCallback", "([Ljava/lang/String;)V");
865 
866     clazz = FindClassOrDie(env, "java/lang/String");
867     gStringClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
868 
869     return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteConnection", sMethods,
870                                 NELEM(sMethods));
871 }
872 
873 } // namespace android
874