forked from mirrors/gecko-dev
		
	 eeb8cf2781
			
		
	
	
		eeb8cf2781
		
	
	
	
	
		
			
			The new method is mandatory because mozStorageTransaction constructor no longer
starts the transaction. It must be started explicitely.
All consumers have been adjusted, but only dom/quota, dom/indexedDB, dom/cache,
dom/localstorage and dom/storage handle the error. Other components like
netwerk/cache, netwerk/cookie and toolkit/components currently only warn on
failure to start a transaction. Bug 1696129, 1696130 and 1696133 have been
filed for proper handling of transaction start failures in those components.
Differential Revision: https://phabricator.services.mozilla.com/D106893
		
	
			
		
			
				
	
	
		
			526 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			526 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* 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 "LocalStorageManager.h"
 | |
| #include "StorageUtils.h"
 | |
| 
 | |
| #include "mozIStorageBindingParams.h"
 | |
| #include "mozIStorageValueArray.h"
 | |
| #include "mozIStorageFunction.h"
 | |
| #include "mozilla/BasePrincipal.h"
 | |
| #include "nsVariant.h"
 | |
| #include "mozilla/Tokenizer.h"
 | |
| #include "mozIStorageConnection.h"
 | |
| #include "mozStorageHelper.h"
 | |
| 
 | |
| // Current version of the database schema
 | |
| #define CURRENT_SCHEMA_VERSION 2
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| using namespace StorageUtils;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class nsReverseStringSQLFunction final : public mozIStorageFunction {
 | |
|   ~nsReverseStringSQLFunction() = default;
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_MOZISTORAGEFUNCTION
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(nsReverseStringSQLFunction, mozIStorageFunction)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsReverseStringSQLFunction::OnFunctionCall(
 | |
|     mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult) {
 | |
|   nsresult rv;
 | |
| 
 | |
|   nsAutoCString stringToReverse;
 | |
|   rv = aFunctionArguments->GetUTF8String(0, stringToReverse);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsAutoCString result;
 | |
|   ReverseString(stringToReverse, result);
 | |
| 
 | |
|   RefPtr<nsVariant> outVar(new nsVariant());
 | |
|   rv = outVar->SetAsAUTF8String(result);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   outVar.forget(aResult);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| // "scope" to "origin attributes suffix" and "origin key" convertor
 | |
| 
 | |
| class ExtractOriginData : protected mozilla::Tokenizer {
 | |
|  public:
 | |
|   ExtractOriginData(const nsACString& scope, nsACString& suffix,
 | |
|                     nsACString& origin)
 | |
|       : mozilla::Tokenizer(scope) {
 | |
|     using mozilla::OriginAttributes;
 | |
| 
 | |
|     // Parse optional appId:isInIsolatedMozBrowserElement: string, in case
 | |
|     // we don't find it, the scope is our new origin key and suffix
 | |
|     // is empty.
 | |
|     suffix.Truncate();
 | |
|     origin.Assign(scope);
 | |
| 
 | |
|     // Bail out if it isn't appId.
 | |
|     // AppId doesn't exist any more but we could have old storage data...
 | |
|     uint32_t appId;
 | |
|     if (!ReadInteger(&appId)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Should be followed by a colon.
 | |
|     if (!CheckChar(':')) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Bail out if it isn't 'isolatedBrowserFlag'.
 | |
|     nsDependentCSubstring isolatedBrowserFlag;
 | |
|     if (!ReadWord(isolatedBrowserFlag)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     bool inIsolatedMozBrowser = isolatedBrowserFlag == "t";
 | |
|     bool notInIsolatedBrowser = isolatedBrowserFlag == "f";
 | |
|     if (!inIsolatedMozBrowser && !notInIsolatedBrowser) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Should be followed by a colon.
 | |
|     if (!CheckChar(':')) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // OK, we have found appId and inIsolatedMozBrowser flag, create the suffix
 | |
|     // from it and take the rest as the origin key.
 | |
| 
 | |
|     // If the profile went through schema 1 -> schema 0 -> schema 1 switching
 | |
|     // we may have stored the full attributes origin suffix when there were
 | |
|     // more than just appId and inIsolatedMozBrowser set on storage principal's
 | |
|     // OriginAttributes.
 | |
|     //
 | |
|     // To preserve full uniqueness we store this suffix to the scope key.
 | |
|     // Schema 0 code will just ignore it while keeping the scoping unique.
 | |
|     //
 | |
|     // The whole scope string is in one of the following forms (when we are
 | |
|     // here):
 | |
|     //
 | |
|     // "1001:f:^appId=1001&inBrowser=false&addonId=101:gro.allizom.rxd.:https:443"
 | |
|     // "1001:f:gro.allizom.rxd.:https:443"
 | |
|     //         |
 | |
|     //         +- the parser cursor position.
 | |
|     //
 | |
|     // If there is '^', the full origin attributes suffix follows.  We search
 | |
|     // for ':' since it is the delimiter used in the scope string and is never
 | |
|     // contained in the origin attributes suffix.  Remaining string after
 | |
|     // the comma is the reversed-domain+schema+port tuple.
 | |
|     Record();
 | |
|     if (CheckChar('^')) {
 | |
|       Token t;
 | |
|       while (Next(t)) {
 | |
|         if (t.Equals(Token::Char(':'))) {
 | |
|           Claim(suffix);
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       OriginAttributes attrs(inIsolatedMozBrowser);
 | |
|       attrs.CreateSuffix(suffix);
 | |
|     }
 | |
| 
 | |
|     // Consume the rest of the input as "origin".
 | |
|     origin.Assign(Substring(mCursor, mEnd));
 | |
|   }
 | |
| };
 | |
| 
 | |
| class GetOriginParticular final : public mozIStorageFunction {
 | |
|  public:
 | |
|   enum EParticular { ORIGIN_ATTRIBUTES_SUFFIX, ORIGIN_KEY };
 | |
| 
 | |
|   explicit GetOriginParticular(EParticular aParticular)
 | |
|       : mParticular(aParticular) {}
 | |
| 
 | |
|  private:
 | |
|   GetOriginParticular() = delete;
 | |
|   ~GetOriginParticular() = default;
 | |
| 
 | |
|   EParticular mParticular;
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_MOZISTORAGEFUNCTION
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(GetOriginParticular, mozIStorageFunction)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GetOriginParticular::OnFunctionCall(mozIStorageValueArray* aFunctionArguments,
 | |
|                                     nsIVariant** aResult) {
 | |
|   nsresult rv;
 | |
| 
 | |
|   nsAutoCString scope;
 | |
|   rv = aFunctionArguments->GetUTF8String(0, scope);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsAutoCString suffix, origin;
 | |
|   ExtractOriginData extractor(scope, suffix, origin);
 | |
| 
 | |
|   nsCOMPtr<nsIWritableVariant> outVar(new nsVariant());
 | |
| 
 | |
|   switch (mParticular) {
 | |
|     case EParticular::ORIGIN_ATTRIBUTES_SUFFIX:
 | |
|       rv = outVar->SetAsAUTF8String(suffix);
 | |
|       break;
 | |
|     case EParticular::ORIGIN_KEY:
 | |
|       rv = outVar->SetAsAUTF8String(origin);
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   outVar.forget(aResult);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| class StripOriginAddonId final : public mozIStorageFunction {
 | |
|  public:
 | |
|   explicit StripOriginAddonId() = default;
 | |
| 
 | |
|  private:
 | |
|   ~StripOriginAddonId() = default;
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_MOZISTORAGEFUNCTION
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(StripOriginAddonId, mozIStorageFunction)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| StripOriginAddonId::OnFunctionCall(mozIStorageValueArray* aFunctionArguments,
 | |
|                                    nsIVariant** aResult) {
 | |
|   nsresult rv;
 | |
| 
 | |
|   nsAutoCString suffix;
 | |
|   rv = aFunctionArguments->GetUTF8String(0, suffix);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // Deserialize and re-serialize to automatically drop any obsolete origin
 | |
|   // attributes.
 | |
|   OriginAttributes oa;
 | |
|   bool ok = oa.PopulateFromSuffix(suffix);
 | |
|   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 | |
| 
 | |
|   nsAutoCString newSuffix;
 | |
|   oa.CreateSuffix(newSuffix);
 | |
| 
 | |
|   nsCOMPtr<nsIWritableVariant> outVar = new nsVariant();
 | |
|   rv = outVar->SetAsAUTF8String(newSuffix);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   outVar.forget(aResult);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult CreateSchema1Tables(mozIStorageConnection* aWorkerConnection) {
 | |
|   nsresult rv;
 | |
| 
 | |
|   rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|       "CREATE TABLE IF NOT EXISTS webappsstore2 ("
 | |
|       "originAttributes TEXT, "
 | |
|       "originKey TEXT, "
 | |
|       "scope TEXT, "  // Only for schema0 downgrade compatibility
 | |
|       "key TEXT, "
 | |
|       "value TEXT)"));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = aWorkerConnection->ExecuteSimpleSQL(
 | |
|       nsLiteralCString("CREATE UNIQUE INDEX IF NOT EXISTS origin_key_index"
 | |
|                        " ON webappsstore2(originAttributes, originKey, key)"));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult TablesExist(mozIStorageConnection* aWorkerConnection,
 | |
|                      bool* aWebappsstore2Exists, bool* aWebappsstoreExists,
 | |
|                      bool* aMoz_webappsstoreExists) {
 | |
|   nsresult rv =
 | |
|       aWorkerConnection->TableExists("webappsstore2"_ns, aWebappsstore2Exists);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   rv = aWorkerConnection->TableExists("webappsstore"_ns, aWebappsstoreExists);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   rv = aWorkerConnection->TableExists("moz_webappsstore"_ns,
 | |
|                                       aMoz_webappsstoreExists);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult CreateCurrentSchemaOnEmptyTableInternal(
 | |
|     mozIStorageConnection* aWorkerConnection) {
 | |
|   nsresult rv = CreateSchema1Tables(aWorkerConnection);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = aWorkerConnection->SetSchemaVersion(CURRENT_SCHEMA_VERSION);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| namespace StorageDBUpdater {
 | |
| 
 | |
| nsresult CreateCurrentSchema(mozIStorageConnection* aConnection) {
 | |
|   mozStorageTransaction transaction(aConnection, false);
 | |
| 
 | |
|   nsresult rv = transaction.Start();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
| #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|   {
 | |
|     int32_t schemaVer;
 | |
|     nsresult rv = aConnection->GetSchemaVersion(&schemaVer);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     MOZ_DIAGNOSTIC_ASSERT(0 == schemaVer);
 | |
| 
 | |
|     bool webappsstore2Exists, webappsstoreExists, moz_webappsstoreExists;
 | |
|     rv = TablesExist(aConnection, &webappsstore2Exists, &webappsstoreExists,
 | |
|                      &moz_webappsstoreExists);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     MOZ_DIAGNOSTIC_ASSERT(!webappsstore2Exists && !webappsstoreExists &&
 | |
|                           !moz_webappsstoreExists);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   rv = CreateCurrentSchemaOnEmptyTableInternal(aConnection);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = transaction.Commit();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult Update(mozIStorageConnection* aWorkerConnection) {
 | |
|   mozStorageTransaction transaction(aWorkerConnection, false);
 | |
| 
 | |
|   nsresult rv = transaction.Start();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   bool doVacuum = false;
 | |
| 
 | |
|   int32_t schemaVer;
 | |
|   rv = aWorkerConnection->GetSchemaVersion(&schemaVer);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // downgrade (v0) -> upgrade (v1+) specific code
 | |
|   if (schemaVer >= 1) {
 | |
|     bool schema0IndexExists;
 | |
|     rv = aWorkerConnection->IndexExists("scope_key_index"_ns,
 | |
|                                         &schema0IndexExists);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     if (schema0IndexExists) {
 | |
|       // If this index exists, the database (already updated to schema >1)
 | |
|       // has been run again on schema 0 code.  That recreated that index
 | |
|       // and might store some new rows while updating only the 'scope' column.
 | |
|       // For such added rows we must fill the new 'origin*' columns correctly
 | |
|       // otherwise there would be a data loss.  The safest way to do it is to
 | |
|       // simply run the whole update to schema 1 again.
 | |
|       schemaVer = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   switch (schemaVer) {
 | |
|     case 0: {
 | |
|       bool webappsstore2Exists, webappsstoreExists, moz_webappsstoreExists;
 | |
|       rv = TablesExist(aWorkerConnection, &webappsstore2Exists,
 | |
|                        &webappsstoreExists, &moz_webappsstoreExists);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       if (!webappsstore2Exists && !webappsstoreExists &&
 | |
|           !moz_webappsstoreExists) {
 | |
|         // The database is empty, this is the first start.  Just create the
 | |
|         // schema table and break to the next version to update to, i.e. bypass
 | |
|         // update from the old version.
 | |
| 
 | |
|         // XXX What does "break to the next version to update to" mean here? It
 | |
|         // seems to refer to the 'break' statement below, but that breaks out of
 | |
|         // the 'switch' statement and continues with committing the transaction.
 | |
|         // Either this is wrong, or the comment above is misleading.
 | |
| 
 | |
|         rv = CreateCurrentSchemaOnEmptyTableInternal(aWorkerConnection);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       doVacuum = true;
 | |
| 
 | |
|       // Ensure Gecko 1.9.1 storage table
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(
 | |
|           nsLiteralCString("CREATE TABLE IF NOT EXISTS webappsstore2 ("
 | |
|                            "scope TEXT, "
 | |
|                            "key TEXT, "
 | |
|                            "value TEXT, "
 | |
|                            "secure INTEGER, "
 | |
|                            "owner TEXT)"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(
 | |
|           nsLiteralCString("CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index"
 | |
|                            " ON webappsstore2(scope, key)"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       nsCOMPtr<mozIStorageFunction> function1(new nsReverseStringSQLFunction());
 | |
|       NS_ENSURE_TRUE(function1, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|       rv = aWorkerConnection->CreateFunction("REVERSESTRING"_ns, 1, function1);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       // Check if there is storage of Gecko 1.9.0 and if so, upgrade that
 | |
|       // storage to actual webappsstore2 table and drop the obsolete table.
 | |
|       // First process this newer table upgrade to priority potential duplicates
 | |
|       // from older storage table.
 | |
|       if (webappsstoreExists) {
 | |
|         rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|             "INSERT OR IGNORE INTO "
 | |
|             "webappsstore2(scope, key, value, secure, owner) "
 | |
|             "SELECT REVERSESTRING(domain) || '.:', key, value, secure, owner "
 | |
|             "FROM webappsstore"));
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|         rv = aWorkerConnection->ExecuteSimpleSQL("DROP TABLE webappsstore"_ns);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|       }
 | |
| 
 | |
|       // Check if there is storage of Gecko 1.8 and if so, upgrade that storage
 | |
|       // to actual webappsstore2 table and drop the obsolete table. Potential
 | |
|       // duplicates will be ignored.
 | |
|       if (moz_webappsstoreExists) {
 | |
|         rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|             "INSERT OR IGNORE INTO "
 | |
|             "webappsstore2(scope, key, value, secure, owner) "
 | |
|             "SELECT REVERSESTRING(domain) || '.:', key, value, secure, domain "
 | |
|             "FROM moz_webappsstore"));
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|         rv = aWorkerConnection->ExecuteSimpleSQL(
 | |
|             "DROP TABLE moz_webappsstore"_ns);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
|       }
 | |
| 
 | |
|       aWorkerConnection->RemoveFunction("REVERSESTRING"_ns);
 | |
| 
 | |
|       // Update the scoping to match the new implememntation: split to oa suffix
 | |
|       // and origin key First rename the old table, we want to remove some
 | |
|       // columns no longer needed, but even before that drop all indexes from it
 | |
|       // (CREATE IF NOT EXISTS for index on the new table would falsely find the
 | |
|       // index!)
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|           "DROP INDEX IF EXISTS webappsstore2.origin_key_index"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|           "DROP INDEX IF EXISTS webappsstore2.scope_key_index"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|           "ALTER TABLE webappsstore2 RENAME TO webappsstore2_old"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       nsCOMPtr<mozIStorageFunction> oaSuffixFunc(new GetOriginParticular(
 | |
|           GetOriginParticular::ORIGIN_ATTRIBUTES_SUFFIX));
 | |
|       rv = aWorkerConnection->CreateFunction("GET_ORIGIN_SUFFIX"_ns, 1,
 | |
|                                              oaSuffixFunc);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       nsCOMPtr<mozIStorageFunction> originKeyFunc(
 | |
|           new GetOriginParticular(GetOriginParticular::ORIGIN_KEY));
 | |
|       rv = aWorkerConnection->CreateFunction("GET_ORIGIN_KEY"_ns, 1,
 | |
|                                              originKeyFunc);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       // Here we ensure this schema tables when we are updating.
 | |
|       rv = CreateSchema1Tables(aWorkerConnection);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|           "INSERT OR IGNORE INTO "
 | |
|           "webappsstore2 (originAttributes, originKey, scope, key, value) "
 | |
|           "SELECT GET_ORIGIN_SUFFIX(scope), GET_ORIGIN_KEY(scope), scope, key, "
 | |
|           "value "
 | |
|           "FROM webappsstore2_old"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(
 | |
|           "DROP TABLE webappsstore2_old"_ns);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       aWorkerConnection->RemoveFunction("GET_ORIGIN_SUFFIX"_ns);
 | |
|       aWorkerConnection->RemoveFunction("GET_ORIGIN_KEY"_ns);
 | |
| 
 | |
|       rv = aWorkerConnection->SetSchemaVersion(1);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       [[fallthrough]];
 | |
|     }
 | |
|     case 1: {
 | |
|       nsCOMPtr<mozIStorageFunction> oaStripAddonId(new StripOriginAddonId());
 | |
|       rv = aWorkerConnection->CreateFunction("STRIP_ADDON_ID"_ns, 1,
 | |
|                                              oaStripAddonId);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       rv = aWorkerConnection->ExecuteSimpleSQL(nsLiteralCString(
 | |
|           "UPDATE webappsstore2 "
 | |
|           "SET originAttributes = STRIP_ADDON_ID(originAttributes) "
 | |
|           "WHERE originAttributes LIKE '^%'"));
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       aWorkerConnection->RemoveFunction("STRIP_ADDON_ID"_ns);
 | |
| 
 | |
|       rv = aWorkerConnection->SetSchemaVersion(2);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       [[fallthrough]];
 | |
|     }
 | |
|     case CURRENT_SCHEMA_VERSION:
 | |
|       // Ensure the tables and indexes are up.  This is mostly a no-op
 | |
|       // in common scenarios.
 | |
|       rv = CreateSchema1Tables(aWorkerConnection);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       // Nothing more to do here, this is the current schema version
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       MOZ_ASSERT(false);
 | |
|       break;
 | |
|   }  // switch
 | |
| 
 | |
|   rv = transaction.Commit();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   if (doVacuum) {
 | |
|     // In some cases this can make the disk file of the database significantly
 | |
|     // smaller.  VACUUM cannot be executed inside a transaction.
 | |
|     rv = aWorkerConnection->ExecuteSimpleSQL("VACUUM"_ns);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| }  // namespace StorageDBUpdater
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 |