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