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