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