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