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