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