Bug 727264 - Add an extra argument to pass more SQLite query results. Cleanup & simplify bridge. r=blassey
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Mon, 27 Feb 2012 12:28:21 +0100
changeset 87831 ff36792efde97c8409f92fa4ad5644a9caa6a9ef
parent 87815 86f8ab61e7558e76cbf810e532fcc9bafd165942
child 87832 3e6935243310b57940c140238306dab8fefafa51
push id22160
push usermbrubeck@mozilla.com
push dateTue, 28 Feb 2012 17:21:33 +0000
treeherdermozilla-central@dde4e0089a18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey
bugs727264
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 727264 - Add an extra argument to pass more SQLite query results. Cleanup & simplify bridge. r=blassey
mobile/android/base/sqlite/SQLiteBridge.java
mozglue/android/SQLiteBridge.cpp
--- a/mobile/android/base/sqlite/SQLiteBridge.java
+++ b/mobile/android/base/sqlite/SQLiteBridge.java
@@ -21,67 +21,64 @@ import java.util.Set;
 
 /*
  * This class allows using the mozsqlite3 library included with Firefox
  * to read SQLite databases, instead of the Android SQLiteDataBase API,
  * which might use whatever outdated DB is present on the Android system.
  */
 public class SQLiteBridge {
     private static final String LOGTAG = "SQLiteBridge";
+
     // Path to the database. We reopen it every query.
     private String mDb;
+
     // Remember column names from last query result.
     private ArrayList<String> mColumns;
+    private Long[] mQueryResults;
+
+    // Values remembered after a query.
+    private int kResultInsertRowId = 0;
+    private int kResultRowsChanged = 1;
 
     // JNI code in $(topdir)/mozglue/android/..
     private static native void sqliteCall(String aDb, String aQuery,
                                           String[] aParams,
                                           ArrayList<String> aColumns,
+                                          Long[] aUpdateResult,
                                           ArrayList<Object[]> aRes)
         throws SQLiteBridgeException;
 
     // Takes the path to the database we want to access.
     public SQLiteBridge(String aDb) throws SQLiteBridgeException {
         mDb = aDb;
     }
 
     // Executes a simple line of sql.
     public void execSQL(String sql)
                 throws SQLiteBridgeException {
-        try {
-            query(sql, null);
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
+        query(sql, null);
     }
 
     // Executes a simple line of sql. Allow you to bind arguments
     public void execSQL(String sql, String[] bindArgs)
                 throws SQLiteBridgeException {
-        try {
-            query(sql, bindArgs);
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
+        query(sql, bindArgs);
     }
 
     // Executes a DELETE statement on the database
     public int delete(String table, String whereClause, String[] whereArgs)
                throws SQLiteBridgeException {
         StringBuilder sb = new StringBuilder("DELETE from ");
         sb.append(table);
         if (whereClause != null) {
             sb.append(" WHERE " + whereClause);
         }
 
-        try {
-            return getIntResult(sb.toString(), whereArgs, 1);
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
+        query(sb.toString(), whereArgs);
+        return mQueryResults[kResultRowsChanged].intValue();
     }
 
     public Cursor query(String table,
                         String[] columns,
                         String selection,
                         String[] selectionArgs,
                         String groupBy,
                         String having,
@@ -113,24 +110,17 @@ public class SQLiteBridge {
             sb.append(" ORDER BY " + orderBy);
         }
 
         if (limit != null) {
             sb.append(" " + limit);
         }
 
         ArrayList<Object[]> results;
-        try {
-            mColumns = null;
-
-            results = query(sb.toString(), selectionArgs);
-
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
+        results = query(sb.toString(), selectionArgs);
 
         MatrixCursor cursor = new MatrixCursor(mColumns.toArray(new String[0]));
         try {
             for (Object resultRow: results) {
                 Object[] resultColumns = (Object[])resultRow;
                 if (resultColumns.length == mColumns.size())
                     cursor.addRow(resultColumns);
             }
@@ -165,21 +155,18 @@ public class SQLiteBridge {
 
         // XXX - Do we need to bind these values?
         sb.append(" VALUES (");
         sb.append(TextUtils.join(", ", valueNames));
         sb.append(") ");
 
         String[] binds = new String[valueBinds.size()];
         valueBinds.toArray(binds);
-        try {
-            return getIntResult(sb.toString(), binds, 0);
-        } catch (SQLiteBridgeException ex) {
-            throw ex;
-        }
+        query(sb.toString(), binds);
+        return mQueryResults[kResultInsertRowId];
     }
 
     public int update(String table, ContentValues values, String whereClause, String[] whereArgs)
                throws SQLiteBridgeException {
         Set<Entry<String, Object>> valueSet = values.valueSet();
         Iterator<Entry<String, Object>> valueIterator = valueSet.iterator();
         ArrayList<String> valueNames = new ArrayList<String>();
 
@@ -202,81 +189,56 @@ public class SQLiteBridge {
             sb.append(whereClause);
             for (int i = 0; i < whereArgs.length; i++) {
                 valueNames.add(whereArgs[i]);
             }
         }
 
         String[] binds = new String[valueNames.size()];
         valueNames.toArray(binds);
-        try {
-            return getIntResult(sb.toString(), binds, 1);
-        } catch (SQLiteBridgeException ex) {
-            throw ex;
-        }
-    }
 
-    private int getIntResult(String query, String[] params, int resultIndex)
-               throws SQLiteBridgeException {
-        ArrayList<Object[]> results = null;
-        try {
-            mColumns = null;
-            results = query(query, params);
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
-
-        if (results != null) {
-            for (Object resultRow: results) {
-                Object[] resultColumns = (Object[])resultRow;
-                return ((Number)resultColumns[resultIndex]).intValue();
-            }
-        }
-        return -1;
+        query(sb.toString(), binds);
+        return mQueryResults[kResultRowsChanged].intValue();
     }
 
     public int getVersion()
                throws SQLiteBridgeException {
         ArrayList<Object[]> results = null;
-        try {
-            mColumns = null;
-            results = query("PRAGMA user_version");
-        } catch(SQLiteBridgeException ex) {
-            throw ex;
-        }
+        results = query("PRAGMA user_version");
         int ret = -1;
         if (results != null) {
             for (Object resultRow: results) {
                 Object[] resultColumns = (Object[])resultRow;
                 String version = (String)resultColumns[0];
                 ret = Integer.parseInt(version);
             }
         }
         return ret;
     }
 
-
     // Do an SQL query without parameters
     public ArrayList<Object[]> query(String aQuery) throws SQLiteBridgeException {
-        String[] params = new String[0];
-        return query(aQuery, params);
+        return query(aQuery, null);
     }
 
     // Do an SQL query, substituting the parameters in the query with the passed
     // parameters. The parameters are subsituded in order, so named parameters
     // are not supported.
     // The result is returned as an ArrayList<Object[]>, with each
     // row being an entry in the ArrayList, and each column being one Object
     // in the Object[] array. The columns are of type null,
     // direct ByteBuffer (BLOB), or String (everything else).
     public ArrayList<Object[]> query(String aQuery, String[] aParams)
         throws SQLiteBridgeException {
         ArrayList<Object[]> result = new ArrayList<Object[]>();
+        mQueryResults = new Long[2];
         mColumns = new ArrayList<String>();
-        sqliteCall(mDb, aQuery, aParams, mColumns, result);
+
+        sqliteCall(mDb, aQuery, aParams, mColumns, mQueryResults, result);
+
         return result;
     }
 
     // Gets the index in the row Object[] for the given column name.
     // Returns -1 if not found.
     public int getColumnIndex(String aColumnName) {
         return mColumns.lastIndexOf(aColumnName);
     }
--- a/mozglue/android/SQLiteBridge.cpp
+++ b/mozglue/android/SQLiteBridge.cpp
@@ -90,20 +90,22 @@ void setup_sqlite_functions(void *sqlite
   GETFUNC(sqlite3_changes);
   GETFUNC(sqlite3_last_insert_rowid);
 #undef GETFUNC
 }
 
 static bool initialized = false;
 static jclass stringClass;
 static jclass objectClass;
+static jclass longClass;
 static jclass byteBufferClass;
 static jclass arrayListClass;
 static jmethodID jByteBufferAllocateDirect;
 static jmethodID jArrayListAdd;
+static jmethodID jLongConstructor;
 static jobject jNull;
 
 static void
 JNI_Throw(JNIEnv* jenv, const char* name, const char* msg)
 {
     jclass cls = jenv->FindClass(name);
     if (cls == NULL) {
         LOG("Couldn't find exception class (or exception pending)\n");
@@ -118,51 +120,59 @@ JNI_Throw(JNIEnv* jenv, const char* name
 
 static void
 JNI_Setup(JNIEnv* jenv)
 {
     if (initialized) return;
 
     objectClass     = jenv->FindClass("java/lang/Object");
     stringClass     = jenv->FindClass("java/lang/String");
+    longClass       = jenv->FindClass("java/lang/Long");
     byteBufferClass = jenv->FindClass("java/nio/ByteBuffer");
     arrayListClass  = jenv->FindClass("java/util/ArrayList");
     jNull           = jenv->NewGlobalRef(NULL);
 
     if (stringClass == NULL || objectClass == NULL
-        || byteBufferClass == NULL || arrayListClass == NULL) {
+        || byteBufferClass == NULL || arrayListClass == NULL
+        || longClass == NULL) {
         LOG("Error finding classes");
         JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
                   "FindClass error");
         return;
     }
 
     // public static ByteBuffer allocateDirect(int capacity)
     jByteBufferAllocateDirect =
         jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
     // boolean add(Object o)
     jArrayListAdd =
         jenv->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
+    // new Long(long i)
+    jLongConstructor =
+        jenv->GetMethodID(longClass, "<init>", "(J)V");
 
-    if (jByteBufferAllocateDirect == NULL || jArrayListAdd == NULL) {
+    if (jByteBufferAllocateDirect == NULL
+        || jArrayListAdd == NULL
+        || jLongConstructor == NULL) {
         LOG("Error finding methods");
         JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
                   "GetMethodId error");
         return;
     }
 
     initialized = true;
 }
 
 extern "C" NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
                                                       jstring jDb,
                                                       jstring jQuery,
                                                       jobjectArray jParams,
                                                       jobject jColumns,
+                                                      jobjectArray jQueryRes,
                                                       jobject jArrayList)
 {
     JNI_Setup(jenv);
 
     char* errorMsg;
     jsize numPars = 0;
 
     const char* queryStr;
@@ -239,39 +249,27 @@ Java_org_mozilla_gecko_sqlite_SQLiteBrid
     cols = f_sqlite3_column_count(ppStmt);
     for (int i = 0; i < cols; i++) {
         const char* colName = f_sqlite3_column_name(ppStmt, i);
         jstring jStr = jenv->NewStringUTF(colName);
         jenv->CallBooleanMethod(jColumns, jArrayListAdd, jStr);
         jenv->DeleteLocalRef(jStr);
     }
 
-    // if the statement doesn't return any results, instead return the id and number of changed rows
-    if (rc == SQLITE_DONE) {
-        jclass integerClass = jenv->FindClass("java/lang/Integer");
-        jmethodID intConstructor = jenv->GetMethodID(integerClass, "<init>", "(I)V");
-        
-        jobjectArray jRow = jenv->NewObjectArray(2, objectClass, NULL);
-        if (jRow == NULL) {
-            asprintf(&errorMsg, "Can't allocate jRow Object[]\n");
-            goto error_close;
-        }
-
-        int id = f_sqlite3_last_insert_rowid(db);
-        jobject jId = jenv->NewObject(integerClass, intConstructor, id);
-        jenv->SetObjectArrayElement(jRow, 0, jId);
+    // Return the id and number of changed rows in jQueryRes
+    {
+        long id = f_sqlite3_last_insert_rowid(db);
+        jobject jId = jenv->NewObject(longClass, jLongConstructor, id);
+        jenv->SetObjectArrayElement(jQueryRes, 0, jId);
         jenv->DeleteLocalRef(jId);
 
-        int changed = f_sqlite3_changes(db);
-        jobject jChanged = jenv->NewObject(integerClass, intConstructor, changed);
-        jenv->SetObjectArrayElement(jRow, 1, jChanged);
+        long changed = f_sqlite3_changes(db);
+        jobject jChanged = jenv->NewObject(longClass, jLongConstructor, changed);
+        jenv->SetObjectArrayElement(jQueryRes, 1, jChanged);
         jenv->DeleteLocalRef(jChanged);
-
-        jenv->CallBooleanMethod(jArrayList, jArrayListAdd, jRow);
-        jenv->DeleteLocalRef(jRow);
     }
 
     // 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[]