Bug 658303 - mozIStorageConnection::Clone() should copy over pragmas.
authorMarco Bonardo <mbonardo@mozilla.com>
Mon, 03 Oct 2011 21:55:03 +0200
changeset 81251 8b6d54721fa1ad19d0ce9266f0c67ab1284dad45
parent 81227 86d559a09cb062f4f58d9e1c92aa2b8910cbd485
child 81252 749fa4c40b381950cf857adf96992af2f25f3aea
push id434
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 12:10:54 +0000
treeherdermozilla-beta@bddb6ed8dd47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs658303
milestone10.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 658303 - mozIStorageConnection::Clone() should copy over pragmas. r=sdwilsh
storage/public/mozIStorageConnection.idl
storage/src/mozStorageConnection.cpp
storage/test/unit/test_storage_connection.js
toolkit/components/places/nsPlacesAutoComplete.js
--- a/storage/public/mozIStorageConnection.idl
+++ b/storage/public/mozIStorageConnection.idl
@@ -99,16 +99,26 @@ interface mozIStorageConnection : nsISup
   /**
    * Clones a database and makes the clone read only if needed.
    *
    * @note If your connection is already read-only, you will get a read-only
    *       clone.
    * @note Due to a bug in SQLite, if you use the shared cache (openDatabase),
    *       you end up with the same privileges as the first connection opened
    *       regardless of what is specified in aReadOnly.
+   * @note The following pragmas are copied over to a read-only clone:
+   *        - cache_size
+   *        - temp_store
+   *       The following pragmas are copied over to a writeable clone:
+   *        - cache_size
+   *        - temp_store
+   *        - foreign_keys
+   *        - journal_size_limit
+   *        - synchronous
+   *        - wal_autocheckpoint
    *
    * @throws NS_ERROR_UNEXPECTED
    *         If this connection is a memory database.
    *
    * @param aReadOnly
    *        If true, the returned database should be put into read-only mode.
    *        Defaults to false.
    * @return the cloned database connection.
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -877,16 +877,46 @@ Connection::Clone(bool aReadOnly,
     flags = (~SQLITE_OPEN_CREATE & flags);
   }
   nsRefPtr<Connection> clone = new Connection(mStorageService, flags);
   NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = clone->initialize(mDatabaseFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Copy over pragmas from the original connection.
+  static const char * pragmas[] = {
+    "cache_size",
+    "temp_store",
+    "foreign_keys",
+    "journal_size_limit",
+    "synchronous",
+    "wal_autocheckpoint",
+  };
+  for (PRUint32 i = 0; i < ArrayLength(pragmas); ++i) {
+    // Read-only connections just need cache_size and temp_store pragmas.
+    if (aReadOnly && ::strcmp(pragmas[i], "cache_size") != 0 &&
+                     ::strcmp(pragmas[i], "temp_store") != 0) {
+      continue;
+    }
+
+    nsCAutoString pragmaQuery("PRAGMA ");
+    pragmaQuery.Append(pragmas[i]);
+    nsCOMPtr<mozIStorageStatement> stmt;
+    rv = CreateStatement(pragmaQuery, getter_AddRefs(stmt));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    bool hasResult = false;
+    if (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+      pragmaQuery.AppendLiteral(" = ");
+      pragmaQuery.AppendInt(stmt->AsInt32(0));
+      rv = clone->ExecuteSimpleSQL(pragmaQuery);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+    }
+  }
+
   // Copy any functions that have been added to this connection.
   (void)mFunctions.EnumerateRead(copyFunctionEnumerator, clone);
 
   NS_ADDREF(*_connection = clone);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/storage/test/unit/test_storage_connection.js
+++ b/storage/test/unit/test_storage_connection.js
@@ -477,16 +477,98 @@ function test_clone_copies_overridden_fu
         db2.close();
       });
     });
   });
 
   run_next_test();
 }
 
+function test_clone_copies_pragmas()
+{
+  const PRAGMAS = [
+    { name: "cache_size", value: 500, copied: true },
+    { name: "temp_store", value: 2, copied: true },
+    { name: "foreign_keys", value: 1, copied: true },
+    { name: "journal_size_limit", value: 524288, copied: true },
+    { name: "synchronous", value: 2, copied: true },
+    { name: "wal_autocheckpoint", value: 16, copied: true },
+    { name: "ignore_check_constraints", value: 1, copied: false },
+  ];
+
+  let db1 = getService().openUnsharedDatabase(getTestDB());
+
+  // Sanity check initial values are different from enforced ones.
+  PRAGMAS.forEach(function (pragma) {
+    let stmt = db1.createStatement("PRAGMA " + pragma.name);
+    do_check_true(stmt.executeStep());
+    do_check_neq(pragma.value, stmt.getInt32(0));
+    stmt.finalize();
+  });
+  // Execute pragmas.
+  PRAGMAS.forEach(function (pragma) {
+    db1.executeSimpleSQL("PRAGMA " + pragma.name + " = " + pragma.value);
+  });
+
+  let db2 = db1.clone();
+  do_check_true(db2.connectionReady);
+
+  // Check cloned connection inherited pragma values.
+  PRAGMAS.forEach(function (pragma) {
+    let stmt = db2.createStatement("PRAGMA " + pragma.name);
+    do_check_true(stmt.executeStep());
+    let validate = pragma.copied ? do_check_eq : do_check_neq;
+    validate(pragma.value, stmt.getInt32(0));
+    stmt.finalize();
+  });
+
+  run_next_test();
+}
+
+function test_readonly_clone_copies_pragmas()
+{
+  const PRAGMAS = [
+    { name: "cache_size", value: 500, copied: true },
+    { name: "temp_store", value: 2, copied: true },
+    { name: "foreign_keys", value: 1, copied: false },
+    { name: "journal_size_limit", value: 524288, copied: false },
+    { name: "synchronous", value: 2, copied: false },
+    { name: "wal_autocheckpoint", value: 16, copied: false },
+    { name: "ignore_check_constraints", value: 1, copied: false },
+  ];
+
+  let db1 = getService().openUnsharedDatabase(getTestDB());
+
+  // Sanity check initial values are different from enforced ones.
+  PRAGMAS.forEach(function (pragma) {
+    let stmt = db1.createStatement("PRAGMA " + pragma.name);
+    do_check_true(stmt.executeStep());
+    do_check_neq(pragma.value, stmt.getInt32(0));
+    stmt.finalize();
+  });
+  // Execute pragmas.
+  PRAGMAS.forEach(function (pragma) {
+    db1.executeSimpleSQL("PRAGMA " + pragma.name + " = " + pragma.value);
+  });
+
+  let db2 = db1.clone(true);
+  do_check_true(db2.connectionReady);
+
+  // Check cloned connection inherited pragma values.
+  PRAGMAS.forEach(function (pragma) {
+    let stmt = db2.createStatement("PRAGMA " + pragma.name);
+    do_check_true(stmt.executeStep());
+    let validate = pragma.copied ? do_check_eq : do_check_neq;
+    validate(pragma.value, stmt.getInt32(0));
+    stmt.finalize();
+  });
+
+  run_next_test();
+}
+
 function test_getInterface()
 {
   let db = getOpenedDatabase();
   let target = db.QueryInterface(Ci.nsIInterfaceRequestor)
                  .getInterface(Ci.nsIEventTarget);
   // Just check that target is non-null.  Other tests will ensure that it has
   // the correct value.
   do_check_true(target != null);
@@ -520,15 +602,17 @@ function test_getInterface()
   test_close_does_not_spin_event_loop, // must be ran before executeAsync tests
   test_asyncClose_succeeds_with_finalized_async_statement,
   test_close_fails_with_async_statement_ran,
   test_clone_optional_param,
   test_clone_readonly,
   test_close_clone_fails,
   test_clone_copies_functions,
   test_clone_copies_overridden_functions,
+  test_clone_copies_pragmas,
+  test_readonly_clone_copies_pragmas,
   test_getInterface,
 ].forEach(add_test);
 
 function run_test()
 {
   run_next_test();
 }
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -108,19 +108,16 @@ const kBrowserUrlbarBranch = "browser.ur
 /**
  * Initializes our temporary table on a given database.
  *
  * @param aDatabase
  *        The mozIStorageConnection to set up the temp table on.
  */
 function initTempTable(aDatabase)
 {
-  // Keep our temporary table in memory.
-  aDatabase.executeSimpleSQL("PRAGMA temp_store = MEMORY");
-
   // Note: this should be kept up-to-date with the definition in
   //       nsPlacesTables.h.
   let stmt = aDatabase.createAsyncStatement(
     "CREATE TEMP TABLE moz_openpages_temp ( "
   + "  url TEXT PRIMARY KEY "
   + ", open_count INTEGER "
   + ") "
   );