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