diff options
Diffstat (limited to 'core/jni/android_database_SQLiteDatabase.cpp')
-rw-r--r-- | core/jni/android_database_SQLiteDatabase.cpp | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp deleted file mode 100644 index 28c421d..0000000 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Copyright (C) 2006-2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "SqliteDatabaseCpp" - -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/String16.h> - -#include <jni.h> -#include <JNIHelp.h> -#include <android_runtime/AndroidRuntime.h> - -#include <sqlite3.h> -#include <sqlite3_android.h> -#include <string.h> -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include <ctype.h> - -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <string.h> -#include <netdb.h> -#include <sys/ioctl.h> - -#include "sqlite3_exception.h" - -#define UTF16_STORAGE 0 -#define INVALID_VERSION -1 -#define ANDROID_TABLE "android_metadata" -/* uncomment the next line to force-enable logging of all statements */ -// #define DB_LOG_STATEMENTS - -#define DEBUG_JNI 0 - -namespace android { - -enum { - OPEN_READWRITE = 0x00000000, - OPEN_READONLY = 0x00000001, - OPEN_READ_MASK = 0x00000001, - NO_LOCALIZED_COLLATORS = 0x00000010, - CREATE_IF_NECESSARY = 0x10000000 -}; - -static jfieldID offset_db_handle; -static jmethodID method_custom_function_callback; -static jclass string_class; -static jint sSqliteSoftHeapLimit = 0; - -static char *createStr(const char *path, short extra) { - int len = strlen(path) + extra; - char *str = (char *)malloc(len + 1); - strncpy(str, path, len); - str[len] = NULL; - return str; -} - -static void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) { - // skip printing this message if it is due to certain types of errors - if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT) return; - // print databasename, errorcode and msg - ALOGI("sqlite returned: error code = %d, msg = %s, db=%s\n", iErrCode, zMsg, databaseName); -} - -// register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. -static void registerLoggingFunc(const char *path) { - static bool loggingFuncSet = false; - if (loggingFuncSet) { - return; - } - - ALOGV("Registering sqlite logging func \n"); - int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path, 0)); - if (err != SQLITE_OK) { - ALOGW("sqlite returned error = %d when trying to register logging func.\n", err); - return; - } - loggingFuncSet = true; -} - -/* public native void dbopen(String path, int flags, String locale); */ -static void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags) -{ - int err; - sqlite3 * handle = NULL; - sqlite3_stmt * statement = NULL; - char const * path8 = env->GetStringUTFChars(pathString, NULL); - int sqliteFlags; - - // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. - registerLoggingFunc(path8); - - // convert our flags into the sqlite flags - if (flags & CREATE_IF_NECESSARY) { - sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - } else if (flags & OPEN_READONLY) { - sqliteFlags = SQLITE_OPEN_READONLY; - } else { - sqliteFlags = SQLITE_OPEN_READWRITE; - } - - err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL); - if (err != SQLITE_OK) { - ALOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags); - throw_sqlite3_exception(env, handle); - goto done; - } - - // The soft heap limit prevents the page cache allocations from growing - // beyond the given limit, no matter what the max page cache sizes are - // set to. The limit does not, as of 3.5.0, affect any other allocations. - sqlite3_soft_heap_limit(sSqliteSoftHeapLimit); - - // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY - err = sqlite3_busy_timeout(handle, 1000 /* ms */); - if (err != SQLITE_OK) { - ALOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8); - throw_sqlite3_exception(env, handle); - goto done; - } - -#ifdef DB_INTEGRITY_CHECK - static const char* integritySql = "pragma integrity_check(1);"; - err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL); - if (err != SQLITE_OK) { - ALOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8); - throw_sqlite3_exception(env, handle); - goto done; - } - - // first is OK or error message - err = sqlite3_step(statement); - if (err != SQLITE_ROW) { - ALOGE("integrity check failed for \"%s\"\n", integritySql, path8); - throw_sqlite3_exception(env, handle); - goto done; - } else { - const char *text = (const char*)sqlite3_column_text(statement, 0); - if (strcmp(text, "ok") != 0) { - ALOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text); - jniThrowException(env, "android/database/sqlite/SQLiteDatabaseCorruptException", text); - goto done; - } - } -#endif - - err = register_android_functions(handle, UTF16_STORAGE); - if (err) { - throw_sqlite3_exception(env, handle); - goto done; - } - - ALOGV("Opened '%s' - %p\n", path8, handle); - env->SetIntField(object, offset_db_handle, (int) handle); - handle = NULL; // The caller owns the handle now. - -done: - // Release allocated resources - if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8); - if (statement != NULL) sqlite3_finalize(statement); - if (handle != NULL) sqlite3_close(handle); -} - -static char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName, short connNum) { - char const *path = env->GetStringUTFChars(databaseName, NULL); - if (path == NULL) { - ALOGE("Failure in getDatabaseName(). VM ran out of memory?\n"); - return NULL; // VM would have thrown OutOfMemoryError - } - char *dbNameStr = createStr(path, 4); - if (connNum > 999) { // TODO: if number of pooled connections > 999, fix this line. - connNum = -1; - } - sprintf(dbNameStr + strlen(path), "|%03d", connNum); - env->ReleaseStringUTFChars(databaseName, path); - return dbNameStr; -} - -static void sqlTrace(void *databaseName, const char *sql) { - ALOGI("sql_statement|%s|%s\n", (char *)databaseName, sql); -} - -/* public native void enableSqlTracing(); */ -static void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName, jshort connType) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName, connType)); -} - -static void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) { - double d = tm/1000000.0; - ALOGI("elapsedTime4Sql|%s|%.3f ms|%s\n", (char *)databaseName, d, sql); -} - -/* public native void enableSqlProfiling(); */ -static void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName, jshort connType) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName, - connType)); -} - -/* public native void close(); */ -static void dbclose(JNIEnv* env, jobject object) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - - if (handle != NULL) { - // release the memory associated with the traceFuncArg in enableSqlTracing function - void *traceFuncArg = sqlite3_trace(handle, &sqlTrace, NULL); - if (traceFuncArg != NULL) { - free(traceFuncArg); - } - // release the memory associated with the traceFuncArg in enableSqlProfiling function - traceFuncArg = sqlite3_profile(handle, &sqlProfile, NULL); - if (traceFuncArg != NULL) { - free(traceFuncArg); - } - ALOGV("Closing database: handle=%p\n", handle); - int result = sqlite3_close(handle); - if (result == SQLITE_OK) { - ALOGV("Closed %p\n", handle); - env->SetIntField(object, offset_db_handle, 0); - } else { - // This can happen if sub-objects aren't closed first. Make sure the caller knows. - throw_sqlite3_exception(env, handle); - ALOGE("sqlite3_close(%p) failed: %d\n", handle, result); - } - } -} - -/* native int native_getDbLookaside(); */ -static jint native_getDbLookaside(JNIEnv* env, jobject object) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - int pCur = -1; - int unused; - sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0); - return pCur; -} - -/* set locale in the android_metadata table, install localized collators, and rebuild indexes */ -static void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags) -{ - if ((flags & NO_LOCALIZED_COLLATORS)) return; - - int err; - char const* locale8 = env->GetStringUTFChars(localeString, NULL); - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - sqlite3_stmt* stmt = NULL; - char** meta = NULL; - int rowCount, colCount; - char* dbLocale = NULL; - - // create the table, if necessary and possible - if (!(flags & OPEN_READONLY)) { - static const char *createSql ="CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)"; - err = sqlite3_exec(handle, createSql, NULL, NULL, NULL); - if (err != SQLITE_OK) { - ALOGE("CREATE TABLE " ANDROID_TABLE " failed\n"); - throw_sqlite3_exception(env, handle); - goto done; - } - } - - // try to read from the table - static const char *selectSql = "SELECT locale FROM " ANDROID_TABLE " LIMIT 1"; - err = sqlite3_get_table(handle, selectSql, &meta, &rowCount, &colCount, NULL); - if (err != SQLITE_OK) { - ALOGE("SELECT locale FROM " ANDROID_TABLE " failed\n"); - throw_sqlite3_exception(env, handle); - goto done; - } - - dbLocale = (rowCount >= 1) ? meta[colCount] : NULL; - - if (dbLocale != NULL && !strcmp(dbLocale, locale8)) { - // database locale is the same as the desired locale; set up the collators and go - err = register_localized_collators(handle, locale8, UTF16_STORAGE); - if (err != SQLITE_OK) throw_sqlite3_exception(env, handle); - goto done; // no database changes needed - } - - if ((flags & OPEN_READONLY)) { - // read-only database, so we're going to have to put up with whatever we got - // For registering new index. Not for modifing the read-only database. - err = register_localized_collators(handle, locale8, UTF16_STORAGE); - if (err != SQLITE_OK) throw_sqlite3_exception(env, handle); - goto done; - } - - // need to update android_metadata and indexes atomically, so use a transaction... - err = sqlite3_exec(handle, "BEGIN TRANSACTION", NULL, NULL, NULL); - if (err != SQLITE_OK) { - ALOGE("BEGIN TRANSACTION failed setting locale\n"); - throw_sqlite3_exception(env, handle); - goto done; - } - - err = register_localized_collators(handle, locale8, UTF16_STORAGE); - if (err != SQLITE_OK) { - ALOGE("register_localized_collators() failed setting locale\n"); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL); - if (err != SQLITE_OK) { - ALOGE("DELETE failed setting locale\n"); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);"; - err = sqlite3_prepare_v2(handle, sql, -1, &stmt, NULL); - if (err != SQLITE_OK) { - ALOGE("sqlite3_prepare_v2(\"%s\") failed\n", sql); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - err = sqlite3_bind_text(stmt, 1, locale8, -1, SQLITE_TRANSIENT); - if (err != SQLITE_OK) { - ALOGE("sqlite3_bind_text() failed setting locale\n"); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - err = sqlite3_step(stmt); - if (err != SQLITE_OK && err != SQLITE_DONE) { - ALOGE("sqlite3_step(\"%s\") failed setting locale\n", sql); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - err = sqlite3_exec(handle, "REINDEX LOCALIZED", NULL, NULL, NULL); - if (err != SQLITE_OK) { - ALOGE("REINDEX LOCALIZED failed\n"); - throw_sqlite3_exception(env, handle); - goto rollback; - } - - // all done, yay! - err = sqlite3_exec(handle, "COMMIT TRANSACTION", NULL, NULL, NULL); - if (err != SQLITE_OK) { - ALOGE("COMMIT TRANSACTION failed setting locale\n"); - throw_sqlite3_exception(env, handle); - goto done; - } - -rollback: - if (err != SQLITE_OK) { - sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); - } - -done: - if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8); - if (stmt != NULL) sqlite3_finalize(stmt); - if (meta != NULL) sqlite3_free_table(meta); -} - -static void native_setSqliteSoftHeapLimit(JNIEnv* env, jobject clazz, jint limit) { - sSqliteSoftHeapLimit = limit; -} - -static jint native_releaseMemory(JNIEnv *env, jobject clazz) -{ - // Attempt to release as much memory from the - return sqlite3_release_memory(sSqliteSoftHeapLimit); -} - -static void native_finalize(JNIEnv* env, jobject object, jint statementId) -{ - if (statementId > 0) { - sqlite3_finalize((sqlite3_stmt *)statementId); - } -} - -static void custom_function_callback(sqlite3_context * context, int argc, sqlite3_value ** argv) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (!env) { - ALOGE("custom_function_callback cannot call into Java on this thread"); - return; - } - // get global ref to CustomFunction object from our user data - jobject function = (jobject)sqlite3_user_data(context); - - // pack up the arguments into a string array - jobjectArray strArray = env->NewObjectArray(argc, string_class, NULL); - if (!strArray) - goto done; - for (int i = 0; i < argc; i++) { - char* arg = (char *)sqlite3_value_text(argv[i]); - if (!arg) { - ALOGE("NULL argument in custom_function_callback. This should not happen."); - return; - } - jobject obj = env->NewStringUTF(arg); - if (!obj) - goto done; - env->SetObjectArrayElement(strArray, i, obj); - env->DeleteLocalRef(obj); - } - - env->CallVoidMethod(function, method_custom_function_callback, strArray); - env->DeleteLocalRef(strArray); - -done: - if (env->ExceptionCheck()) { - ALOGE("An exception was thrown by custom sqlite3 function."); - LOGE_EX(env); - env->ExceptionClear(); - } -} - -static jint native_addCustomFunction(JNIEnv* env, jobject object, - jstring name, jint numArgs, jobject function) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - char const *nameStr = env->GetStringUTFChars(name, NULL); - jobject ref = env->NewGlobalRef(function); - ALOGD_IF(DEBUG_JNI, "native_addCustomFunction %s ref: %p", nameStr, ref); - int err = sqlite3_create_function(handle, nameStr, numArgs, SQLITE_UTF8, - (void *)ref, custom_function_callback, NULL, NULL); - env->ReleaseStringUTFChars(name, nameStr); - - if (err == SQLITE_OK) - return (int)ref; - else { - ALOGE("sqlite3_create_function returned %d", err); - env->DeleteGlobalRef(ref); - throw_sqlite3_exception(env, handle); - return 0; - } -} - -static void native_releaseCustomFunction(JNIEnv* env, jobject object, jint ref) -{ - ALOGD_IF(DEBUG_JNI, "native_releaseCustomFunction %d", ref); - env->DeleteGlobalRef((jobject)ref); -} - -static JNINativeMethod sMethods[] = -{ - /* name, signature, funcPtr */ - {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen}, - {"dbclose", "()V", (void *)dbclose}, - {"enableSqlTracing", "(Ljava/lang/String;S)V", (void *)enableSqlTracing}, - {"enableSqlProfiling", "(Ljava/lang/String;S)V", (void *)enableSqlProfiling}, - {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale}, - {"native_getDbLookaside", "()I", (void *)native_getDbLookaside}, - {"native_setSqliteSoftHeapLimit", "(I)V", (void *)native_setSqliteSoftHeapLimit}, - {"releaseMemory", "()I", (void *)native_releaseMemory}, - {"native_finalize", "(I)V", (void *)native_finalize}, - {"native_addCustomFunction", - "(Ljava/lang/String;ILandroid/database/sqlite/SQLiteDatabase$CustomFunction;)I", - (void *)native_addCustomFunction}, - {"native_releaseCustomFunction", "(I)V", (void *)native_releaseCustomFunction}, -}; - -int register_android_database_SQLiteDatabase(JNIEnv *env) -{ - jclass clazz; - - clazz = env->FindClass("android/database/sqlite/SQLiteDatabase"); - if (clazz == NULL) { - ALOGE("Can't find android/database/sqlite/SQLiteDatabase\n"); - return -1; - } - - string_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/String")); - if (string_class == NULL) { - ALOGE("Can't find java/lang/String\n"); - return -1; - } - - offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I"); - if (offset_db_handle == NULL) { - ALOGE("Can't find SQLiteDatabase.mNativeHandle\n"); - return -1; - } - - clazz = env->FindClass("android/database/sqlite/SQLiteDatabase$CustomFunction"); - if (clazz == NULL) { - ALOGE("Can't find android/database/sqlite/SQLiteDatabase$CustomFunction\n"); - return -1; - } - method_custom_function_callback = env->GetMethodID(clazz, "callback", "([Ljava/lang/String;)V"); - if (method_custom_function_callback == NULL) { - ALOGE("Can't find method SQLiteDatabase.CustomFunction.callback\n"); - return -1; - } - - return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", - sMethods, NELEM(sMethods)); -} - -/* throw a SQLiteException with a message appropriate for the error in handle */ -void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) { - throw_sqlite3_exception(env, handle, NULL); -} - -/* throw a SQLiteException with the given message */ -void throw_sqlite3_exception(JNIEnv* env, const char* message) { - throw_sqlite3_exception(env, NULL, message); -} - -/* throw a SQLiteException with a message appropriate for the error in handle - concatenated with the given message - */ -void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) { - if (handle) { - throw_sqlite3_exception(env, sqlite3_errcode(handle), - sqlite3_errmsg(handle), message); - } else { - // we use SQLITE_OK so that a generic SQLiteException is thrown; - // any code not specified in the switch statement below would do. - throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message); - } -} - -/* throw a SQLiteException for a given error code */ -void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) { - if (errcode == SQLITE_DONE) { - throw_sqlite3_exception(env, errcode, NULL, message); - } else { - char temp[21]; - sprintf(temp, "error code %d", errcode); - throw_sqlite3_exception(env, errcode, temp, message); - } -} - -/* throw a SQLiteException for a given error code, sqlite3message, and - user message - */ -void throw_sqlite3_exception(JNIEnv* env, int errcode, - const char* sqlite3Message, const char* message) { - const char* exceptionClass; - switch (errcode) { - case SQLITE_IOERR: - exceptionClass = "android/database/sqlite/SQLiteDiskIOException"; - break; - case SQLITE_CORRUPT: - case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also - exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException"; - break; - case SQLITE_CONSTRAINT: - exceptionClass = "android/database/sqlite/SQLiteConstraintException"; - break; - case SQLITE_ABORT: - exceptionClass = "android/database/sqlite/SQLiteAbortException"; - break; - case SQLITE_DONE: - exceptionClass = "android/database/sqlite/SQLiteDoneException"; - break; - case SQLITE_FULL: - exceptionClass = "android/database/sqlite/SQLiteFullException"; - break; - case SQLITE_MISUSE: - exceptionClass = "android/database/sqlite/SQLiteMisuseException"; - break; - case SQLITE_PERM: - exceptionClass = "android/database/sqlite/SQLiteAccessPermException"; - break; - case SQLITE_BUSY: - exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException"; - break; - case SQLITE_LOCKED: - exceptionClass = "android/database/sqlite/SQLiteTableLockedException"; - break; - case SQLITE_READONLY: - exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException"; - break; - case SQLITE_CANTOPEN: - exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException"; - break; - case SQLITE_TOOBIG: - exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException"; - break; - case SQLITE_RANGE: - exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException"; - break; - case SQLITE_NOMEM: - exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException"; - break; - case SQLITE_MISMATCH: - exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException"; - break; - case SQLITE_UNCLOSED: - exceptionClass = "android/database/sqlite/SQLiteUnfinalizedObjectsException"; - break; - default: - exceptionClass = "android/database/sqlite/SQLiteException"; - break; - } - - if (sqlite3Message != NULL && message != NULL) { - char* fullMessage = (char *)malloc(strlen(sqlite3Message) + strlen(message) + 3); - if (fullMessage != NULL) { - strcpy(fullMessage, sqlite3Message); - strcat(fullMessage, ": "); - strcat(fullMessage, message); - jniThrowException(env, exceptionClass, fullMessage); - free(fullMessage); - } else { - jniThrowException(env, exceptionClass, sqlite3Message); - } - } else if (sqlite3Message != NULL) { - jniThrowException(env, exceptionClass, sqlite3Message); - } else { - jniThrowException(env, exceptionClass, message); - } -} - - -} // namespace android |