Cherry pick of WebKit commit r49018, fix for b/2067397. Enable Database.changVersion().
diff --git a/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp b/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp
index 300e829..cdcef31 100644
--- a/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8DatabaseCustom.cpp
@@ -45,6 +45,45 @@
 CALLBACK_FUNC_DECL(DatabaseChangeVersion)
 {
     INC_STATS("DOM.Database.changeVersion()");
+
+    if (args.Length() < 2)
+        return throwError("The old and new version strings are required.", V8Proxy::SyntaxError);
+
+    if (!(args[0]->IsString() && args[1]->IsString()))
+        return throwError("The old and new versions must be strings.");
+
+    Database* database = V8DOMWrapper::convertToNativeObject<Database>(V8ClassIndex::DATABASE, args.Holder());
+
+    Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
+    if (!frame)
+        return v8::Undefined();
+
+    RefPtr<V8CustomSQLTransactionCallback> callback;
+    if (args.Length() > 2) {
+        if (!args[2]->IsObject())
+            return throwError("changeVersion transaction callback must be of valid type.");
+
+        callback = V8CustomSQLTransactionCallback::create(args[2], frame);
+    }
+
+    RefPtr<V8CustomSQLTransactionErrorCallback> errorCallback;
+    if (args.Length() > 3) {
+        if (!args[3]->IsObject())
+            return throwError("changeVersion error callback must be of valid type.");
+
+        errorCallback = V8CustomSQLTransactionErrorCallback::create(args[3], frame);
+    }
+
+    RefPtr<V8CustomVoidCallback> successCallback;
+    if (args.Length() > 4) {
+        if (!args[4]->IsObject())
+            return throwError("changeVersion success callback must be of valid type.");
+
+        successCallback = V8CustomVoidCallback::create(args[4], frame);
+    }
+
+    database->changeVersion(toWebCoreString(args[0]), toWebCoreString(args[1]), callback.release(), errorCallback.release(), successCallback.release());
+
     return v8::Undefined();
 }
 
@@ -76,7 +115,7 @@
 
     RefPtr<V8CustomVoidCallback> successCallback;
     if (args.Length() > 2) {
-        if (!args[1]->IsObject())
+        if (!args[2]->IsObject())
             return throwError("Transaction success callback must be of valid type.");
 
         successCallback = V8CustomVoidCallback::create(args[2], frame);
diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp
index 5504cb1..8118e76 100644
--- a/WebCore/storage/Database.cpp
+++ b/WebCore/storage/Database.cpp
@@ -89,6 +89,22 @@
     return map;
 }
 
+// NOTE: Caller must lock guidMutex().
+static inline void updateGuidVersionMap(int guid, String newVersion)
+{
+    // Ensure the the mutex is locked.
+    ASSERT(!guidMutex().tryLock());
+
+    // Note: It is not safe to put an empty string into the guidToVersionMap() map.
+    // That's because the map is cross-thread, but empty strings are per-thread.
+    // The copy() function makes a version of the string you can use on the current
+    // thread, but we need a string we can keep in a cross-thread data structure.
+    // FIXME: This is a quite-awkward restriction to have to program with.
+
+    // Map null string to empty string (see comment above).
+    guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.copy());
+}
+
 typedef HashMap<int, HashSet<Database*>*> GuidDatabaseMap;
 static GuidDatabaseMap& guidToDatabaseMap()
 {
@@ -178,20 +194,6 @@
 
 Database::~Database()
 {
-    {
-        MutexLocker locker(guidMutex());
-
-        HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
-        ASSERT(hashSet);
-        ASSERT(hashSet->contains(this));
-        hashSet->remove(this);
-        if (hashSet->isEmpty()) {
-            guidToDatabaseMap().remove(m_guid);
-            delete hashSet;
-            guidToVersionMap().remove(m_guid);
-        }
-    }
-
     if (m_document->databaseThread())
         m_document->databaseThread()->unscheduleDatabaseTasks(this);
 
@@ -278,6 +280,8 @@
 
 bool Database::setVersionInDatabase(const String& version)
 {
+    // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
+    // clause in the CREATE statement (see Database::performOpenAndVerify()).
     DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoTableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);"));
 
     m_databaseAuthorizer->disable();
@@ -331,6 +335,20 @@
         m_sqliteDatabase.close();
         m_document->databaseThread()->recordDatabaseClosed(this);
         m_opened = false;
+
+        {
+            MutexLocker locker(guidMutex());
+
+            HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
+            ASSERT(hashSet);
+            ASSERT(hashSet->contains(this));
+            hashSet->remove(this);
+            if (hashSet->isEmpty()) {
+                guidToDatabaseMap().remove(m_guid);
+                delete hashSet;
+                guidToVersionMap().remove(m_guid);
+            }
+        }
     }
 }
 
@@ -458,15 +476,9 @@
     {
         MutexLocker locker(guidMutex());
 
-        // Note: It is not safe to put an empty string into the guidToVersionMap() map.
-        // That's because the map is cross-thread, but empty strings are per-thread.
-        // The copy() function makes a version of the string you can use on the current
-        // thread, but we need a string we can keep in a cross-thread data structure.
-        // FIXME: This is a quite-awkward restriction to have to program with.
-
         GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
         if (entry != guidToVersionMap().end()) {
-            // Map null string to empty string (see comment above).
+            // Map null string to empty string (see updateGuidVersionMap()).
             currentVersion = entry->second.isNull() ? String("") : entry->second;
             LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
         } else {
@@ -488,8 +500,7 @@
                 currentVersion = m_expectedVersion;
             }
 
-            // Map empty string to null string (see comment above).
-            guidToVersionMap().set(m_guid, currentVersion.isEmpty() ? String() : currentVersion.copy());
+            updateGuidVersionMap(m_guid, currentVersion);
         }
     }
 
@@ -619,6 +630,9 @@
 void Database::setExpectedVersion(const String& version)
 {
     m_expectedVersion = version.copy();
+    // Update the in memory database version map.
+    MutexLocker locker(guidMutex());
+    updateGuidVersionMap(m_guid, version);
 }
 
 PassRefPtr<SecurityOrigin> Database::securityOriginCopy() const