summaryrefslogtreecommitdiffstats
path: root/mozglue/android/SQLiteBridge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mozglue/android/SQLiteBridge.cpp')
-rw-r--r--mozglue/android/SQLiteBridge.cpp413
1 files changed, 0 insertions, 413 deletions
diff --git a/mozglue/android/SQLiteBridge.cpp b/mozglue/android/SQLiteBridge.cpp
deleted file mode 100644
index 187900bad..000000000
--- a/mozglue/android/SQLiteBridge.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <jni.h>
-#include <android/log.h>
-#include "dlfcn.h"
-#include "APKOpen.h"
-#include "ElfLoader.h"
-#include "SQLiteBridge.h"
-
-#ifdef DEBUG
-#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
-#else
-#define LOG(x...)
-#endif
-
-#define SQLITE_WRAPPER_INT(name) name ## _t f_ ## name;
-
-SQLITE_WRAPPER_INT(sqlite3_open)
-SQLITE_WRAPPER_INT(sqlite3_errmsg)
-SQLITE_WRAPPER_INT(sqlite3_prepare_v2)
-SQLITE_WRAPPER_INT(sqlite3_bind_parameter_count)
-SQLITE_WRAPPER_INT(sqlite3_bind_null)
-SQLITE_WRAPPER_INT(sqlite3_bind_text)
-SQLITE_WRAPPER_INT(sqlite3_step)
-SQLITE_WRAPPER_INT(sqlite3_column_count)
-SQLITE_WRAPPER_INT(sqlite3_finalize)
-SQLITE_WRAPPER_INT(sqlite3_close)
-SQLITE_WRAPPER_INT(sqlite3_column_name)
-SQLITE_WRAPPER_INT(sqlite3_column_type)
-SQLITE_WRAPPER_INT(sqlite3_column_blob)
-SQLITE_WRAPPER_INT(sqlite3_column_bytes)
-SQLITE_WRAPPER_INT(sqlite3_column_text)
-SQLITE_WRAPPER_INT(sqlite3_changes)
-SQLITE_WRAPPER_INT(sqlite3_last_insert_rowid)
-
-void setup_sqlite_functions(void *sqlite_handle)
-{
-#define GETFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(sqlite_handle, #name)
- GETFUNC(sqlite3_open);
- GETFUNC(sqlite3_errmsg);
- GETFUNC(sqlite3_prepare_v2);
- GETFUNC(sqlite3_bind_parameter_count);
- GETFUNC(sqlite3_bind_null);
- GETFUNC(sqlite3_bind_text);
- GETFUNC(sqlite3_step);
- GETFUNC(sqlite3_column_count);
- GETFUNC(sqlite3_finalize);
- GETFUNC(sqlite3_close);
- GETFUNC(sqlite3_column_name);
- GETFUNC(sqlite3_column_type);
- GETFUNC(sqlite3_column_blob);
- GETFUNC(sqlite3_column_bytes);
- GETFUNC(sqlite3_column_text);
- GETFUNC(sqlite3_changes);
- GETFUNC(sqlite3_last_insert_rowid);
-#undef GETFUNC
-}
-
-static bool initialized = false;
-static jclass stringClass;
-static jclass objectClass;
-static jclass byteBufferClass;
-static jclass cursorClass;
-static jmethodID jByteBufferAllocateDirect;
-static jmethodID jCursorConstructor;
-static jmethodID jCursorAddRow;
-
-static jobject sqliteInternalCall(JNIEnv* jenv, sqlite3 *db, jstring jQuery,
- jobjectArray jParams, jlongArray jQueryRes);
-
-static void throwSqliteException(JNIEnv* jenv, const char* aFormat, ...)
-{
- va_list ap;
- va_start(ap, aFormat);
- char* msg = nullptr;
- vasprintf(&msg, aFormat, ap);
- LOG("Error in SQLiteBridge: %s\n", msg);
- JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", msg);
- free(msg);
- va_end(ap);
-}
-
-static void
-JNI_Setup(JNIEnv* jenv)
-{
- if (initialized) return;
-
- jclass lObjectClass = jenv->FindClass("java/lang/Object");
- jclass lStringClass = jenv->FindClass("java/lang/String");
- jclass lByteBufferClass = jenv->FindClass("java/nio/ByteBuffer");
- jclass lCursorClass = jenv->FindClass("org/mozilla/gecko/sqlite/MatrixBlobCursor");
-
- if (lStringClass == nullptr
- || lObjectClass == nullptr
- || lByteBufferClass == nullptr
- || lCursorClass == nullptr) {
- throwSqliteException(jenv, "FindClass error");
- return;
- }
-
- // Those are only local references. Make them global so they work
- // across calls and threads.
- objectClass = (jclass)jenv->NewGlobalRef(lObjectClass);
- stringClass = (jclass)jenv->NewGlobalRef(lStringClass);
- byteBufferClass = (jclass)jenv->NewGlobalRef(lByteBufferClass);
- cursorClass = (jclass)jenv->NewGlobalRef(lCursorClass);
-
- if (stringClass == nullptr || objectClass == nullptr
- || byteBufferClass == nullptr
- || cursorClass == nullptr) {
- throwSqliteException(jenv, "NewGlobalRef error");
- return;
- }
-
- // public static ByteBuffer allocateDirect(int capacity)
- jByteBufferAllocateDirect =
- jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
- // new MatrixBlobCursor(String [])
- jCursorConstructor =
- jenv->GetMethodID(cursorClass, "<init>", "([Ljava/lang/String;)V");
- // public void addRow (Object[] columnValues)
- jCursorAddRow =
- jenv->GetMethodID(cursorClass, "addRow", "([Ljava/lang/Object;)V");
-
- if (jByteBufferAllocateDirect == nullptr
- || jCursorConstructor == nullptr
- || jCursorAddRow == nullptr) {
- throwSqliteException(jenv, "GetMethodId error");
- return;
- }
-
- initialized = true;
-}
-
-extern "C" NS_EXPORT jobject MOZ_JNICALL
-Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
- jstring jDb,
- jstring jQuery,
- jobjectArray jParams,
- jlongArray jQueryRes)
-{
- JNI_Setup(jenv);
-
- int rc;
- jobject jCursor = nullptr;
- const char* dbPath;
- sqlite3 *db;
-
- dbPath = jenv->GetStringUTFChars(jDb, nullptr);
- rc = f_sqlite3_open(dbPath, &db);
- jenv->ReleaseStringUTFChars(jDb, dbPath);
- if (rc != SQLITE_OK) {
- throwSqliteException(jenv,
- "Can't open database: %s", f_sqlite3_errmsg(db));
- f_sqlite3_close(db); // close db even if open failed
- return nullptr;
- }
- jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
- f_sqlite3_close(db);
- return jCursor;
-}
-
-extern "C" NS_EXPORT jobject MOZ_JNICALL
-Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCallWithDb(JNIEnv* jenv, jclass,
- jlong jDb,
- jstring jQuery,
- jobjectArray jParams,
- jlongArray jQueryRes)
-{
- JNI_Setup(jenv);
-
- jobject jCursor = nullptr;
- sqlite3 *db = (sqlite3*)jDb;
- jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
- return jCursor;
-}
-
-extern "C" NS_EXPORT jlong MOZ_JNICALL
-Java_org_mozilla_gecko_sqlite_SQLiteBridge_openDatabase(JNIEnv* jenv, jclass,
- jstring jDb)
-{
- JNI_Setup(jenv);
-
- int rc;
- const char* dbPath;
- sqlite3 *db;
-
- dbPath = jenv->GetStringUTFChars(jDb, nullptr);
- rc = f_sqlite3_open(dbPath, &db);
- jenv->ReleaseStringUTFChars(jDb, dbPath);
- if (rc != SQLITE_OK) {
- throwSqliteException(jenv,
- "Can't open database: %s", f_sqlite3_errmsg(db));
- f_sqlite3_close(db); // close db even if open failed
- return 0;
- }
- return (jlong)db;
-}
-
-extern "C" NS_EXPORT void MOZ_JNICALL
-Java_org_mozilla_gecko_sqlite_SQLiteBridge_closeDatabase(JNIEnv* jenv, jclass,
- jlong jDb)
-{
- JNI_Setup(jenv);
-
- sqlite3 *db = (sqlite3*)jDb;
- f_sqlite3_close(db);
-}
-
-static jobject
-sqliteInternalCall(JNIEnv* jenv,
- sqlite3 *db,
- jstring jQuery,
- jobjectArray jParams,
- jlongArray jQueryRes)
-{
- JNI_Setup(jenv);
-
- jobject jCursor = nullptr;
- jsize numPars = 0;
-
- const char *pzTail;
- sqlite3_stmt *ppStmt;
- int rc;
-
- const char* queryStr;
- queryStr = jenv->GetStringUTFChars(jQuery, nullptr);
-
- rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
- if (rc != SQLITE_OK || ppStmt == nullptr) {
- throwSqliteException(jenv,
- "Can't prepare statement: %s", f_sqlite3_errmsg(db));
- return nullptr;
- }
- jenv->ReleaseStringUTFChars(jQuery, queryStr);
-
- // Check if number of parameters matches
- if (jParams != nullptr) {
- numPars = jenv->GetArrayLength(jParams);
- }
- int sqlNumPars;
- sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt);
- if (numPars != sqlNumPars) {
- throwSqliteException(jenv,
- "Passed parameter count (%d) "
- "doesn't match SQL parameter count (%d)",
- numPars, sqlNumPars);
- return nullptr;
- }
-
- if (jParams != nullptr) {
- // Bind parameters, if any
- if (numPars > 0) {
- for (int i = 0; i < numPars; i++) {
- jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i);
- // IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
- // should be OK.
- jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
- if (isString != JNI_TRUE) {
- throwSqliteException(jenv,
- "Parameter is not of String type");
- return nullptr;
- }
-
- // SQLite parameters index from 1.
- if (jObjectParam == nullptr) {
- rc = f_sqlite3_bind_null(ppStmt, i + 1);
- } else {
- jstring jStringParam = (jstring) jObjectParam;
- const char* paramStr = jenv->GetStringUTFChars(jStringParam, nullptr);
- rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
- jenv->ReleaseStringUTFChars(jStringParam, paramStr);
- }
-
- if (rc != SQLITE_OK) {
- throwSqliteException(jenv, "Error binding query parameter");
- return nullptr;
- }
- }
- }
- }
-
- // Execute the query and step through the results
- rc = f_sqlite3_step(ppStmt);
- if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
- throwSqliteException(jenv,
- "Can't step statement: (%d) %s", rc, f_sqlite3_errmsg(db));
- return nullptr;
- }
-
- // Get the column count and names
- int cols;
- cols = f_sqlite3_column_count(ppStmt);
-
- {
- // Allocate a String[cols]
- jobjectArray jStringArray = jenv->NewObjectArray(cols,
- stringClass,
- nullptr);
- if (jStringArray == nullptr) {
- throwSqliteException(jenv, "Can't allocate String[]");
- return nullptr;
- }
-
- // Assign column names to the String[]
- for (int i = 0; i < cols; i++) {
- const char* colName = f_sqlite3_column_name(ppStmt, i);
- jstring jStr = jenv->NewStringUTF(colName);
- jenv->SetObjectArrayElement(jStringArray, i, jStr);
- }
-
- // Construct the MatrixCursor(String[]) with given column names
- jCursor = jenv->NewObject(cursorClass,
- jCursorConstructor,
- jStringArray);
- if (jCursor == nullptr) {
- throwSqliteException(jenv, "Can't allocate MatrixBlobCursor");
- return nullptr;
- }
- }
-
- // Return the id and number of changed rows in jQueryRes
- {
- jlong id = f_sqlite3_last_insert_rowid(db);
- jenv->SetLongArrayRegion(jQueryRes, 0, 1, &id);
-
- jlong changed = f_sqlite3_changes(db);
- jenv->SetLongArrayRegion(jQueryRes, 1, 1, &changed);
- }
-
- // For each row, add an Object[] to the passed ArrayList,
- // with that containing either String or ByteArray objects
- // containing the columns
- while (rc != SQLITE_DONE) {
- // Process row
- // Construct Object[]
- jobjectArray jRow = jenv->NewObjectArray(cols,
- objectClass,
- nullptr);
- if (jRow == nullptr) {
- throwSqliteException(jenv, "Can't allocate jRow Object[]");
- return nullptr;
- }
-
- for (int i = 0; i < cols; i++) {
- int colType = f_sqlite3_column_type(ppStmt, i);
- if (colType == SQLITE_BLOB) {
- // Treat as blob
- const void* blob = f_sqlite3_column_blob(ppStmt, i);
- int colLen = f_sqlite3_column_bytes(ppStmt, i);
-
- // Construct ByteBuffer of correct size
- jobject jByteBuffer =
- jenv->CallStaticObjectMethod(byteBufferClass,
- jByteBufferAllocateDirect,
- colLen);
- if (jByteBuffer == nullptr) {
- throwSqliteException(jenv,
- "Failure calling ByteBuffer.allocateDirect");
- return nullptr;
- }
-
- // Get its backing array
- void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer);
- if (bufferArray == nullptr) {
- throwSqliteException(jenv,
- "Failure calling GetDirectBufferAddress");
- return nullptr;
- }
- memcpy(bufferArray, blob, colLen);
-
- jenv->SetObjectArrayElement(jRow, i, jByteBuffer);
- jenv->DeleteLocalRef(jByteBuffer);
- } else if (colType == SQLITE_NULL) {
- jenv->SetObjectArrayElement(jRow, i, nullptr);
- } else {
- // Treat everything else as text
- const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i);
- jstring jStr = jenv->NewStringUTF(txt);
- jenv->SetObjectArrayElement(jRow, i, jStr);
- jenv->DeleteLocalRef(jStr);
- }
- }
-
- // Append Object[] to Cursor
- jenv->CallVoidMethod(jCursor, jCursorAddRow, jRow);
-
- // Clean up
- jenv->DeleteLocalRef(jRow);
-
- // Get next row
- rc = f_sqlite3_step(ppStmt);
- // Real error?
- if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
- throwSqliteException(jenv,
- "Can't re-step statement:(%d) %s", rc, f_sqlite3_errmsg(db));
- return nullptr;
- }
- }
-
- rc = f_sqlite3_finalize(ppStmt);
- if (rc != SQLITE_OK) {
- throwSqliteException(jenv,
- "Can't finalize statement: %s", f_sqlite3_errmsg(db));
- return nullptr;
- }
-
- return jCursor;
-}