19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006-2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef LOG_TAG
18fb16cbd9b2e86d6878d4bff820422bc09c8938deVasu Nori#define LOG_TAG "SqliteDatabaseCpp"
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String8.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String16.h>
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <jni.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <JNIHelp.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sqlite3.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sqlite3_android.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
313b4062eeb01be33951ba214e027da523cf09f8b1Mathias Agopian#include <utils/Log.h>
323b4062eeb01be33951ba214e027da523cf09f8b1Mathias Agopian#include <utils/threads.h>
333b4062eeb01be33951ba214e027da523cf09f8b1Mathias Agopian#include <utils/List.h>
343b4062eeb01be33951ba214e027da523cf09f8b1Mathias Agopian#include <utils/Errors.h>
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ctype.h>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/socket.h>
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/in.h>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netdb.h>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/ioctl.h>
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "sqlite3_exception.h"
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define UTF16_STORAGE 0
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define INVALID_VERSION -1
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ANDROID_TABLE "android_metadata"
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* uncomment the next line to force-enable logging of all statements */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// #define DB_LOG_STATEMENTS
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5377267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori#define DEBUG_JNI 0
5477267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectenum {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READWRITE          = 0x00000000,
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READONLY           = 0x00000001,
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READ_MASK          = 0x00000001,
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NO_LOCALIZED_COLLATORS  = 0x00000010,
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CREATE_IF_NECESSARY     = 0x10000000
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID offset_db_handle;
669d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwoodstatic jmethodID method_custom_function_callback;
67b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwoodstatic jclass string_class;
6834ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Noristatic jint sSqliteSoftHeapLimit = 0;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
706c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Noristatic char *createStr(const char *path, short extra) {
716c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    int len = strlen(path) + extra;
72bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    char *str = (char *)malloc(len + 1);
73bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    strncpy(str, path, len);
74bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    str[len] = NULL;
75bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    return str;
76bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori}
77bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori
7854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) {
79cc17ed29e0ff184afd1bce750f4f80aa917cfcafVasu Nori    // skip printing this message if it is due to certain types of errors
80060e25bf124c530423c589622c220828a7f35086Vasu Nori    if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT) return;
815be894e636522addc40dad3b631f0249e6cc25cfVasu Nori    // print databasename, errorcode and msg
825be894e636522addc40dad3b631f0249e6cc25cfVasu Nori    LOGI("sqlite returned: error code = %d, msg = %s, db=%s\n", iErrCode, zMsg, databaseName);
8354dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
8454dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
8554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori// register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called.
86bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Noristatic void registerLoggingFunc(const char *path) {
8754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    static bool loggingFuncSet = false;
8854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    if (loggingFuncSet) {
8954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        return;
9054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    }
9154dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
9254dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    LOGV("Registering sqlite logging func \n");
936c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path, 0));
9491d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori    if (err != SQLITE_OK) {
95f7ebe8e8564108c020fc0d89b833635d210b38a8Vasu Nori        LOGW("sqlite returned error = %d when trying to register logging func.\n", err);
9691d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori        return;
9791d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori    }
9854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    loggingFuncSet = true;
9954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
10054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* public native void dbopen(String path, int flags, String locale); */
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags)
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = NULL;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = NULL;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char const * path8 = env->GetStringUTFChars(pathString, NULL);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int sqliteFlags;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called.
111bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    registerLoggingFunc(path8);
11254dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // convert our flags into the sqlite flags
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (flags & CREATE_IF_NECESSARY) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (flags & OPEN_READONLY) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READONLY;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READWRITE;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The soft heap limit prevents the page cache allocations from growing
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // beyond the given limit, no matter what the max page cache sizes are
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // set to. The limit does not, as of 3.5.0, affect any other allocations.
13234ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori    sqlite3_soft_heap_limit(sSqliteSoftHeapLimit);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_busy_timeout(handle, 1000 /* ms */);
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef DB_INTEGRITY_CHECK
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char* integritySql = "pragma integrity_check(1);";
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8);
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // first is OK or error message
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_step(statement);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_ROW) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("integrity check failed for \"%s\"\n", integritySql, path8);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *text = (const char*)sqlite3_column_text(statement, 0);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (strcmp(text, "ok") != 0) {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text);
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, "android/database/sqlite/SQLiteDatabaseCorruptException", text);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto done;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = register_android_functions(handle, UTF16_STORAGE);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGV("Opened '%s' - %p\n", path8, handle);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->SetIntField(object, offset_db_handle, (int) handle);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    handle = NULL;  // The caller owns the handle now.
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectdone:
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Release allocated resources
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8);
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (statement != NULL) sqlite3_finalize(statement);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle != NULL) sqlite3_close(handle);
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1846c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Noristatic char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName, short connNum) {
18554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    char const *path = env->GetStringUTFChars(databaseName, NULL);
18654dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    if (path == NULL) {
18754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        LOGE("Failure in getDatabaseName(). VM ran out of memory?\n");
18854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        return NULL; // VM would have thrown OutOfMemoryError
18954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    }
1906c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    char *dbNameStr = createStr(path, 4);
1916c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    if (connNum > 999) { // TODO: if number of pooled connections > 999, fix this line.
1926c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori      connNum = -1;
1936c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    }
1946c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    sprintf(dbNameStr + strlen(path), "|%03d", connNum);
19554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    env->ReleaseStringUTFChars(databaseName, path);
19654dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    return dbNameStr;
19754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
19854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
19954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlTrace(void *databaseName, const char *sql) {
2003ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    LOGI("sql_statement|%s|%s\n", (char *)databaseName, sql);
2013ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2023ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
2033ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori/* public native void enableSqlTracing(); */
2046c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Noristatic void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName, jshort connType)
2053ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori{
2063ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2076c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName, connType));
2083ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2093ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
21054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) {
2113ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    double d = tm/1000000.0;
2123ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    LOGI("elapsedTime4Sql|%s|%.3f ms|%s\n", (char *)databaseName, d, sql);
2133ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2143ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
2153ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori/* public native void enableSqlProfiling(); */
2166c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Noristatic void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName, jshort connType)
2173ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori{
2183ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2196c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName,
2206c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori            connType));
2213ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2223ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* public native void close(); */
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void dbclose(JNIEnv* env, jobject object)
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle != NULL) {
2293ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        // release the memory associated with the traceFuncArg in enableSqlTracing function
2303ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        void *traceFuncArg = sqlite3_trace(handle, &sqlTrace, NULL);
2313ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        if (traceFuncArg != NULL) {
2323ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori            free(traceFuncArg);
2333ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        }
2343ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        // release the memory associated with the traceFuncArg in enableSqlProfiling function
2353ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        traceFuncArg = sqlite3_profile(handle, &sqlProfile, NULL);
2363ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        if (traceFuncArg != NULL) {
2373ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori            free(traceFuncArg);
2383ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGV("Closing database: handle=%p\n", handle);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int result = sqlite3_close(handle);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (result == SQLITE_OK) {
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGV("Closed %p\n", handle);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->SetIntField(object, offset_db_handle, 0);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, handle);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("sqlite3_close(%p) failed: %d\n", handle, result);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
252c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori/* native int native_getDbLookaside(); */
253c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noristatic jint native_getDbLookaside(JNIEnv* env, jobject object)
254c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori{
255c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
256c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    int pCur = -1;
257c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    int unused;
258c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0);
259c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    return pCur;
260c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori}
261c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* set locale in the android_metadata table, install localized collators, and rebuild indexes */
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags)
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & NO_LOCALIZED_COLLATORS)) return;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char const* locale8 = env->GetStringUTFChars(localeString, NULL);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt* stmt = NULL;
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char** meta = NULL;
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int rowCount, colCount;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char* dbLocale = NULL;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // create the table, if necessary and possible
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!(flags & OPEN_READONLY)) {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static const char *createSql ="CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)";
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = sqlite3_exec(handle, createSql, NULL, NULL, NULL);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("CREATE TABLE " ANDROID_TABLE " failed\n");
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, handle);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto done;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // try to read from the table
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char *selectSql = "SELECT locale FROM " ANDROID_TABLE " LIMIT 1";
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_get_table(handle, selectSql, &meta, &rowCount, &colCount, NULL);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("SELECT locale FROM " ANDROID_TABLE " failed\n");
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
295b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa    dbLocale = (rowCount >= 1) ? meta[colCount] : NULL;
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dbLocale != NULL && !strcmp(dbLocale, locale8)) {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // database locale is the same as the desired locale; set up the collators and go
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;   // no database changes needed
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & OPEN_READONLY)) {
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // read-only database, so we're going to have to put up with whatever we got
306b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa        // For registering new index. Not for modifing the read-only database.
307b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa        err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // need to update android_metadata and indexes atomically, so use a transaction...
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "BEGIN TRANSACTION", NULL, NULL, NULL);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("BEGIN TRANSACTION failed setting locale\n");
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
320b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa    err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("register_localized_collators() failed setting locale\n");
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
32478f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori        goto rollback;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("DELETE failed setting locale\n");
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);";
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_prepare_v2(handle, sql, -1, &stmt, NULL);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_prepare_v2(\"%s\") failed\n", sql);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_bind_text(stmt, 1, locale8, -1, SQLITE_TRANSIENT);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_bind_text() failed setting locale\n");
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_step(stmt);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK && err != SQLITE_DONE) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_step(\"%s\") failed setting locale\n", sql);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "REINDEX LOCALIZED", NULL, NULL, NULL);
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("REINDEX LOCALIZED failed\n");
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // all done, yay!
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "COMMIT TRANSACTION", NULL, NULL, NULL);
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("COMMIT TRANSACTION failed setting locale\n");
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectrollback:
37278f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori    if (err != SQLITE_OK) {
37378f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori        sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
37478f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori    }
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectdone:
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8);
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (stmt != NULL) sqlite3_finalize(stmt);
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (meta != NULL) sqlite3_free_table(meta);
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38234ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Noristatic void native_setSqliteSoftHeapLimit(JNIEnv* env, jobject clazz, jint limit) {
38334ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori    sSqliteSoftHeapLimit = limit;
38434ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori}
38534ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint native_releaseMemory(JNIEnv *env, jobject clazz)
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Attempt to release as much memory from the
38934ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori    return sqlite3_release_memory(sSqliteSoftHeapLimit);
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3926f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Noristatic void native_finalize(JNIEnv* env, jobject object, jint statementId)
3936f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori{
3946f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori    if (statementId > 0) {
3956f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori        sqlite3_finalize((sqlite3_stmt *)statementId);
3966f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori    }
3976f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori}
3986f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori
3999d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwoodstatic void custom_function_callback(sqlite3_context * context, int argc, sqlite3_value ** argv) {
4009d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    JNIEnv* env = AndroidRuntime::getJNIEnv();
4019d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    if (!env) {
4029d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        LOGE("custom_function_callback cannot call into Java on this thread");
4039d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        return;
4049d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    }
405c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    // get global ref to CustomFunction object from our user data
406c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    jobject function = (jobject)sqlite3_user_data(context);
4079d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4089d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    // pack up the arguments into a string array
409c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    jobjectArray strArray = env->NewObjectArray(argc, string_class, NULL);
410c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    if (!strArray)
411c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        goto done;
4129d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    for (int i = 0; i < argc; i++) {
4139d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        char* arg = (char *)sqlite3_value_text(argv[i]);
414c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        if (!arg) {
415c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood            LOGE("NULL argument in custom_function_callback.  This should not happen.");
4169d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood            return;
4179d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        }
418c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        jobject obj = env->NewStringUTF(arg);
419c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        if (!obj)
420c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood            goto done;
4219d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        env->SetObjectArrayElement(strArray, i, obj);
4229d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        env->DeleteLocalRef(obj);
4239d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    }
4249d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4259d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    env->CallVoidMethod(function, method_custom_function_callback, strArray);
426b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood    env->DeleteLocalRef(strArray);
427c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood
428c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwooddone:
429c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    if (env->ExceptionCheck()) {
430c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        LOGE("An exception was thrown by custom sqlite3 function.");
431c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        LOGE_EX(env);
432c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood        env->ExceptionClear();
433c5bb8d8de5297c610c0c75897e025cbd6aec8ddaMike Lockwood    }
4349d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood}
4359d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4369d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwoodstatic jint native_addCustomFunction(JNIEnv* env, jobject object,
4379d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        jstring name, jint numArgs, jobject function)
4389d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood{
4399d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
4409d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    char const *nameStr = env->GetStringUTFChars(name, NULL);
4419d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    jobject ref = env->NewGlobalRef(function);
44277267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori    LOGD_IF(DEBUG_JNI, "native_addCustomFunction %s ref: %p", nameStr, ref);
4439d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    int err = sqlite3_create_function(handle, nameStr, numArgs, SQLITE_UTF8,
4449d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood            (void *)ref, custom_function_callback, NULL, NULL);
4459d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    env->ReleaseStringUTFChars(name, nameStr);
4469d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4479d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    if (err == SQLITE_OK)
4489d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        return (int)ref;
4499d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    else {
4509d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        LOGE("sqlite3_create_function returned %d", err);
4519d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        env->DeleteGlobalRef(ref);
4529d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        throw_sqlite3_exception(env, handle);
4539d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        return 0;
4549d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood     }
4559d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood}
4569d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4579d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwoodstatic void native_releaseCustomFunction(JNIEnv* env, jobject object, jint ref)
4589d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood{
45977267fc68f2c05ca7cdd1f6b6a9d9b2d4479f8bbVasu Nori    LOGD_IF(DEBUG_JNI, "native_releaseCustomFunction %d", ref);
4609d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    env->DeleteGlobalRef((jobject)ref);
4619d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood}
4629d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] =
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* name, signature, funcPtr */
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen},
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"dbclose", "()V", (void *)dbclose},
4686c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    {"enableSqlTracing", "(Ljava/lang/String;S)V", (void *)enableSqlTracing},
4696c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    {"enableSqlProfiling", "(Ljava/lang/String;S)V", (void *)enableSqlProfiling},
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
471c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
47234ad57f0e844cd97f59d4ab22087d60d58650ba4Vasu Nori    {"native_setSqliteSoftHeapLimit", "(I)V", (void *)native_setSqliteSoftHeapLimit},
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"releaseMemory", "()I", (void *)native_releaseMemory},
4746f37f83a4802a0d411395f3abc5f24a2cfec025dVasu Nori    {"native_finalize", "(I)V", (void *)native_finalize},
4759d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    {"native_addCustomFunction",
4769d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood                    "(Ljava/lang/String;ILandroid/database/sqlite/SQLiteDatabase$CustomFunction;)I",
4779d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood                    (void *)native_addCustomFunction},
4789d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    {"native_releaseCustomFunction", "(I)V", (void *)native_releaseCustomFunction},
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_SQLiteDatabase(JNIEnv *env)
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clazz = env->FindClass("android/database/sqlite/SQLiteDatabase");
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (clazz == NULL) {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find android/database/sqlite/SQLiteDatabase\n");
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
491b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood    string_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/String"));
492b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood    if (string_class == NULL) {
493b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood        LOGE("Can't find java/lang/String\n");
494b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood        return -1;
495b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood    }
496b0f72de87d1abdfec0cd188f277c48f65f7011a8Mike Lockwood
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I");
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (offset_db_handle == NULL) {
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find SQLiteDatabase.mNativeHandle\n");
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5039d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    clazz = env->FindClass("android/database/sqlite/SQLiteDatabase$CustomFunction");
5049d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    if (clazz == NULL) {
5059d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        LOGE("Can't find android/database/sqlite/SQLiteDatabase$CustomFunction\n");
5069d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        return -1;
5079d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    }
5089d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    method_custom_function_callback = env->GetMethodID(clazz, "callback", "([Ljava/lang/String;)V");
5099d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    if (method_custom_function_callback == NULL) {
5109d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        LOGE("Can't find method SQLiteDatabase.CustomFunction.callback\n");
5119d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood        return -1;
5129d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood    }
5139d9c1be296db26c6ad36b8593fb77ca263422665Mike Lockwood
5146c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase",
5156c354da9436e946708fc3f3a1c0d18b18bbfdf43Vasu Nori            sMethods, NELEM(sMethods));
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with a message appropriate for the error in handle */
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    throw_sqlite3_exception(env, handle, NULL);
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with the given message */
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, const char* message) {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    throw_sqlite3_exception(env, NULL, message);
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with a message appropriate for the error in handle
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   concatenated with the given message
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle) {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, sqlite3_errcode(handle),
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                sqlite3_errmsg(handle), message);
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // we use SQLITE_OK so that a generic SQLiteException is thrown;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // any code not specified in the switch statement below would do.
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException for a given error code */
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (errcode == SQLITE_DONE) {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, errcode, NULL, message);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
547f80efdf7e2b34ab8fec8f47052bf8386616ac312Kenny Root        char temp[21];
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sprintf(temp, "error code %d", errcode);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, errcode, temp, message);
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException for a given error code, sqlite3message, and
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   user message
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, int errcode,
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             const char* sqlite3Message, const char* message) {
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* exceptionClass;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    switch (errcode) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_IOERR:
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_CORRUPT:
564b339509d3129db32a57ef95fc322a8482b6994f3Vasu Nori        case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_CONSTRAINT:
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteConstraintException";
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_ABORT:
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteAbortException";
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_DONE:
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteDoneException";
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_FULL:
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteFullException";
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_MISUSE:
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteMisuseException";
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
582dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_PERM:
583dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
584dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
585dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_BUSY:
586dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
587dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
588dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_LOCKED:
589dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
590dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
591dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_READONLY:
592dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
593dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
594dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_CANTOPEN:
595dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
596dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
597dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_TOOBIG:
598dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
599dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
600dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_RANGE:
601dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
602dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
603dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_NOMEM:
604dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
605dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
606dea9713387460c560b67106ab913f686f7d16af2Vasu Nori        case SQLITE_MISMATCH:
607dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
608dea9713387460c560b67106ab913f686f7d16af2Vasu Nori           break;
609422dad0f5069a96c002faf31540bf471a7052585Vasu Nori        case SQLITE_UNCLOSED:
610422dad0f5069a96c002faf31540bf471a7052585Vasu Nori           exceptionClass = "android/database/sqlite/SQLiteUnfinalizedObjectsException";
611422dad0f5069a96c002faf31540bf471a7052585Vasu Nori           break;
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteException";
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (sqlite3Message != NULL && message != NULL) {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char* fullMessage = (char *)malloc(strlen(sqlite3Message) + strlen(message) + 3);
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fullMessage != NULL) {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcpy(fullMessage, sqlite3Message);
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcat(fullMessage, ": ");
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcat(fullMessage, message);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, exceptionClass, fullMessage);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            free(fullMessage);
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, exceptionClass, sqlite3Message);
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (sqlite3Message != NULL) {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, exceptionClass, sqlite3Message);
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, exceptionClass, message);
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
637