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
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "Database"
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 SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024)
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ANDROID_TABLE "android_metadata"
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* uncomment the next line to force-enable logging of all statements */
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// #define DB_LOG_STATEMENTS
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectenum {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READWRITE          = 0x00000000,
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READONLY           = 0x00000001,
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    OPEN_READ_MASK          = 0x00000001,
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NO_LOCALIZED_COLLATORS  = 0x00000010,
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CREATE_IF_NECESSARY     = 0x10000000
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID offset_db_handle;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
66bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Noristatic char *createStr(const char *path) {
67bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    int len = strlen(path);
68bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    char *str = (char *)malloc(len + 1);
69bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    strncpy(str, path, len);
70bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    str[len] = NULL;
71bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    return str;
72bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori}
73bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori
7454dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) {
75cc17ed29e0ff184afd1bce750f4f80aa917cfcafVasu Nori    // skip printing this message if it is due to certain types of errors
76cc17ed29e0ff184afd1bce750f4f80aa917cfcafVasu Nori    if (iErrCode == SQLITE_CONSTRAINT) return;
77cc17ed29e0ff184afd1bce750f4f80aa917cfcafVasu Nori    LOGI("sqlite returned: error code = %d, msg = %s\n", iErrCode, zMsg);
7854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
7954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
8054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori// register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called.
81bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Noristatic void registerLoggingFunc(const char *path) {
8254dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    static bool loggingFuncSet = false;
8354dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    if (loggingFuncSet) {
8454dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        return;
8554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    }
8654dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
8754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    LOGV("Registering sqlite logging func \n");
88bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path));
8991d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori    if (err != SQLITE_OK) {
9091d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori        LOGE("sqlite_config failed error_code = %d. THIS SHOULD NEVER occur.\n", err);
9191d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori        return;
9291d0e3c950846ad0dfa67ac8d67b554880795580Vasu Nori    }
9354dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    loggingFuncSet = true;
9454dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
9554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* public native void dbopen(String path, int flags, String locale); */
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags)
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = NULL;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = NULL;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char const * path8 = env->GetStringUTFChars(pathString, NULL);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int sqliteFlags;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10554dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called.
106bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    registerLoggingFunc(path8);
10754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // convert our flags into the sqlite flags
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (flags & CREATE_IF_NECESSARY) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (flags & OPEN_READONLY) {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READONLY;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sqliteFlags = SQLITE_OPEN_READWRITE;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL);
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags);
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The soft heap limit prevents the page cache allocations from growing
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // beyond the given limit, no matter what the max page cache sizes are
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // set to. The limit does not, as of 3.5.0, affect any other allocations.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_busy_timeout(handle, 1000 /* ms */);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef DB_INTEGRITY_CHECK
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char* integritySql = "pragma integrity_check(1);";
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // first is OK or error message
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_step(statement);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_ROW) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("integrity check failed for \"%s\"\n", integritySql, path8);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const char *text = (const char*)sqlite3_column_text(statement, 0);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (strcmp(text, "ok") != 0) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, "android/database/sqlite/SQLiteDatabaseCorruptException", text);
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto done;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = register_android_functions(handle, UTF16_STORAGE);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LOGV("Opened '%s' - %p\n", path8, handle);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->SetIntField(object, offset_db_handle, (int) handle);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    handle = NULL;  // The caller owns the handle now.
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectdone:
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Release allocated resources
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (statement != NULL) sqlite3_finalize(statement);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle != NULL) sqlite3_close(handle);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName) {
18054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    char const *path = env->GetStringUTFChars(databaseName, NULL);
18154dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    if (path == NULL) {
18254dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        LOGE("Failure in getDatabaseName(). VM ran out of memory?\n");
18354dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori        return NULL; // VM would have thrown OutOfMemoryError
18454dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    }
185bd29b7c2b7f6c4041b270599d4f0a8bbfb4d785bVasu Nori    char *dbNameStr = createStr(path);
18654dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    env->ReleaseStringUTFChars(databaseName, path);
18754dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    return dbNameStr;
18854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori}
18954dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
19054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlTrace(void *databaseName, const char *sql) {
1913ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    LOGI("sql_statement|%s|%s\n", (char *)databaseName, sql);
1923ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
1933ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
1943ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori/* public native void enableSqlTracing(); */
1953ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Noristatic void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName)
1963ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori{
1973ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
19854dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName));
1993ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2003ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
20154dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Noristatic void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) {
2023ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    double d = tm/1000000.0;
2033ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    LOGI("elapsedTime4Sql|%s|%.3f ms|%s\n", (char *)databaseName, d, sql);
2043ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2053ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
2063ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori/* public native void enableSqlProfiling(); */
2073ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Noristatic void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName)
2083ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori{
2093ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
21054dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori    sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName));
2113ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori}
2123ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori
21354dd0f25acad86f7c4901e6f7d8fdd5628e42970Vasu Nori
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* public native void close(); */
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void dbclose(JNIEnv* env, jobject object)
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle != NULL) {
2203ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        // release the memory associated with the traceFuncArg in enableSqlTracing function
2213ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        void *traceFuncArg = sqlite3_trace(handle, &sqlTrace, NULL);
2223ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        if (traceFuncArg != NULL) {
2233ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori            free(traceFuncArg);
2243ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        }
2253ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        // release the memory associated with the traceFuncArg in enableSqlProfiling function
2263ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        traceFuncArg = sqlite3_profile(handle, &sqlProfile, NULL);
2273ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        if (traceFuncArg != NULL) {
2283ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori            free(traceFuncArg);
2293ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori        }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGV("Closing database: handle=%p\n", handle);
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int result = sqlite3_close(handle);
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (result == SQLITE_OK) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGV("Closed %p\n", handle);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->SetIntField(object, offset_db_handle, 0);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, handle);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("sqlite3_close(%p) failed: %d\n", handle, result);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* public native void native_execSQL(String sql); */
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void native_execSQL(JNIEnv* env, jobject object, jstring sqlString)
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int stepErr;
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt * statement = NULL;
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jchar const * sql = env->GetStringChars(sqlString, NULL);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jsize sqlLen = env->GetStringLength(sqlString);
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (sql == NULL || sqlLen == 0) {
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, "java/lang/IllegalArgumentException", "You must supply an SQL string");
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL);
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    env->ReleaseStringChars(sqlString, sql);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), handle, sql8);
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle, sql8);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        env->ReleaseStringUTFChars(sqlString, sql8);
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    stepErr = sqlite3_step(statement);
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_finalize(statement);
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (stepErr != SQLITE_DONE) {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (stepErr == SQLITE_ROW) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, "Queries cannot be performed using execSQL(), use query() instead.");
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), handle, sql8);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, handle, sql8);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->ReleaseStringUTFChars(sqlString, sql8);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifndef DB_LOG_STATEMENTS
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IF_LOGV()
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGV("Success on %p when executing '%s'\n", handle, sql8);
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        env->ReleaseStringUTFChars(sqlString, sql8);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* native long lastInsertRow(); */
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jlong lastInsertRow(JNIEnv* env, jobject object)
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sqlite3_last_insert_rowid(handle);
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* native int lastChangeCount(); */
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint lastChangeCount(JNIEnv* env, jobject object)
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sqlite3_changes(handle);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
310c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori/* native int native_getDbLookaside(); */
311c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Noristatic jint native_getDbLookaside(JNIEnv* env, jobject object)
312c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori{
313c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
314c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    int pCur = -1;
315c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    int unused;
316c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0);
317c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    return pCur;
318c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori}
319c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* set locale in the android_metadata table, install localized collators, and rebuild indexes */
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags)
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & NO_LOCALIZED_COLLATORS)) return;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int err;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char const* locale8 = env->GetStringUTFChars(localeString, NULL);
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sqlite3_stmt* stmt = NULL;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char** meta = NULL;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int rowCount, colCount;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char* dbLocale = NULL;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // create the table, if necessary and possible
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!(flags & OPEN_READONLY)) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static const char *createSql ="CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)";
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = sqlite3_exec(handle, createSql, NULL, NULL, NULL);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) {
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LOGE("CREATE TABLE " ANDROID_TABLE " failed\n");
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw_sqlite3_exception(env, handle);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto done;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // try to read from the table
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char *selectSql = "SELECT locale FROM " ANDROID_TABLE " LIMIT 1";
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_get_table(handle, selectSql, &meta, &rowCount, &colCount, NULL);
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("SELECT locale FROM " ANDROID_TABLE " failed\n");
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
353b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa    dbLocale = (rowCount >= 1) ? meta[colCount] : NULL;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dbLocale != NULL && !strcmp(dbLocale, locale8)) {
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // database locale is the same as the desired locale; set up the collators and go
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;   // no database changes needed
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & OPEN_READONLY)) {
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // read-only database, so we're going to have to put up with whatever we got
364b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa        // For registering new index. Not for modifing the read-only database.
365b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa        err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // need to update android_metadata and indexes atomically, so use a transaction...
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "BEGIN TRANSACTION", NULL, NULL, NULL);
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("BEGIN TRANSACTION failed setting locale\n");
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
378b945639d0c3fa1850c07a2b80f476c8d242a8bdeDaisuke Miyakawa    err = register_localized_collators(handle, locale8, UTF16_STORAGE);
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("register_localized_collators() failed setting locale\n");
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
38278f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori        goto rollback;
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL);
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("DELETE failed setting locale\n");
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);";
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_prepare_v2(handle, sql, -1, &stmt, NULL);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_prepare_v2(\"%s\") failed\n", sql);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_bind_text(stmt, 1, locale8, -1, SQLITE_TRANSIENT);
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_bind_text() failed setting locale\n");
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_step(stmt);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK && err != SQLITE_DONE) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("sqlite3_step(\"%s\") failed setting locale\n", sql);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "REINDEX LOCALIZED", NULL, NULL, NULL);
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("REINDEX LOCALIZED failed\n");
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto rollback;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // all done, yay!
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    err = sqlite3_exec(handle, "COMMIT TRANSACTION", NULL, NULL, NULL);
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != SQLITE_OK) {
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("COMMIT TRANSACTION failed setting locale\n");
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, handle);
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto done;
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectrollback:
43078f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori    if (err != SQLITE_OK) {
43178f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori        sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
43278f307d229466bb41c0260d1092dcea82a7bb5f8Vasu Nori    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectdone:
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8);
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (stmt != NULL) sqlite3_finalize(stmt);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (meta != NULL) sqlite3_free_table(meta);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jint native_releaseMemory(JNIEnv *env, jobject clazz)
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Attempt to release as much memory from the
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT);
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] =
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* name, signature, funcPtr */
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen},
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"dbclose", "()V", (void *)dbclose},
4513ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    {"enableSqlTracing", "(Ljava/lang/String;)V", (void *)enableSqlTracing},
4523ef94e25b4c896ecaa85aa2c12b8863ecdf98df0Vasu Nori    {"enableSqlProfiling", "(Ljava/lang/String;)V", (void *)enableSqlProfiling},
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL},
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"lastInsertRow", "()J", (void *)lastInsertRow},
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"lastChangeCount", "()I", (void *)lastChangeCount},
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
457c3849200fa60b22ea583ba2a6f902d6a632a5e7eVasu Nori    {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {"releaseMemory", "()I", (void *)native_releaseMemory},
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_SQLiteDatabase(JNIEnv *env)
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clazz = env->FindClass("android/database/sqlite/SQLiteDatabase");
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (clazz == NULL) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find android/database/sqlite/SQLiteDatabase\n");
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I");
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (offset_db_handle == NULL) {
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOGE("Can't find SQLiteDatabase.mNativeHandle\n");
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", sMethods, NELEM(sMethods));
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with a message appropriate for the error in handle */
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    throw_sqlite3_exception(env, handle, NULL);
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with the given message */
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, const char* message) {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    throw_sqlite3_exception(env, NULL, message);
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException with a message appropriate for the error in handle
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   concatenated with the given message
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (handle) {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, sqlite3_errcode(handle),
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                sqlite3_errmsg(handle), message);
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // we use SQLITE_OK so that a generic SQLiteException is thrown;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // any code not specified in the switch statement below would do.
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException for a given error code */
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (errcode == SQLITE_DONE) {
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, errcode, NULL, message);
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
509f80efdf7e2b34ab8fec8f47052bf8386616ac312Kenny Root        char temp[21];
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sprintf(temp, "error code %d", errcode);
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, errcode, temp, message);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* throw a SQLiteException for a given error code, sqlite3message, and
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   user message
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid throw_sqlite3_exception(JNIEnv* env, int errcode,
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             const char* sqlite3Message, const char* message) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* exceptionClass;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    switch (errcode) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_IOERR:
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_CORRUPT:
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_CONSTRAINT:
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteConstraintException";
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_ABORT:
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteAbortException";
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_DONE:
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteDoneException";
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_FULL:
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteFullException";
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case SQLITE_MISUSE:
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteMisuseException";
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           exceptionClass = "android/database/sqlite/SQLiteException";
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           break;
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (sqlite3Message != NULL && message != NULL) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char* fullMessage = (char *)malloc(strlen(sqlite3Message) + strlen(message) + 3);
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fullMessage != NULL) {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcpy(fullMessage, sqlite3Message);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcat(fullMessage, ": ");
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcat(fullMessage, message);
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, exceptionClass, fullMessage);
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            free(fullMessage);
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jniThrowException(env, exceptionClass, sqlite3Message);
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (sqlite3Message != NULL) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, exceptionClass, sqlite3Message);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jniThrowException(env, exceptionClass, message);
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
568