[SCM] WebKit Debian packaging branch, webkit-1.3, updated. upstream/1.3.7-4207-g178b198

andreip at google.com andreip at google.com
Sun Feb 20 23:38:22 UTC 2011


The following commit has been merged in the webkit-1.3 branch:
commit d16c15871027638ed9b04d25460f00eb2d7303b4
Author: andreip at google.com <andreip at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Jan 22 15:00:18 2011 +0000

    2011-01-22  Andrei Popescu  <andreip at google.com>
    
            Reviewed by Jeremy Orlow.
    
            IndexedDB corrupts data on disk
            https://bugs.webkit.org/show_bug.cgi?id=52890
    
            * storage/indexeddb/data-corruption-expected.txt: Added.
            * storage/indexeddb/data-corruption.html: Added.
    2011-01-22  Andrei Popescu  <andreip at google.com>
    
            Reviewed by Jeremy Orlow.
    
            IndexedDB corrupts data on disk
            https://bugs.webkit.org/show_bug.cgi?id=52890
    
            We need to store the SerializedScriptValues on disk in a BLOB column rather than TEXT.
            Test: storage/indexeddb/data-corruption.html
    
            * platform/sql/SQLiteStatement.cpp:
            (WebCore::SQLiteStatement::bindBlob):
            (WebCore::SQLiteStatement::getColumnBlobAsString):
            (WebCore::SQLiteStatement::getColumnBlobAsVector):
            * platform/sql/SQLiteStatement.h:
            * storage/IDBCursorBackendImpl.cpp:
            (WebCore::IDBCursorBackendImpl::loadCurrentRow):
            * storage/IDBFactoryBackendImpl.cpp:
            (WebCore::runCommands):
            (WebCore::createTables):
            (WebCore::createMetaDataTable):
            (WebCore::migrateDatabase):
            * storage/IDBObjectStoreBackendImpl.cpp:
            (WebCore::IDBObjectStoreBackendImpl::getInternal):
            (WebCore::putObjectStoreData):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@76448 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 50f5134..838cb0a 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2011-01-22  Andrei Popescu  <andreip at google.com>
+
+        Reviewed by Jeremy Orlow.
+
+        IndexedDB corrupts data on disk
+        https://bugs.webkit.org/show_bug.cgi?id=52890
+
+        * storage/indexeddb/data-corruption-expected.txt: Added.
+        * storage/indexeddb/data-corruption.html: Added.
+
 2011-01-22  Robert Hogan  <robert at webkit.org>
 
         Reviewed by Kenneth Rohde Christiansen.
diff --git a/LayoutTests/storage/indexeddb/data-corruption-expected.txt b/LayoutTests/storage/indexeddb/data-corruption-expected.txt
new file mode 100644
index 0000000..bce3901
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/data-corruption-expected.txt
@@ -0,0 +1,69 @@
+Test that data inserted into IndexedDB does not get corrupted on disk.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+webkitIndexedDB.open('name')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+openSuccess():
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+db = event.result
+db.setVersion('new version')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+setVersionSuccess():
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+trans = event.result
+PASS trans !== null is true
+Deleted all object stores.
+createObjectStore():
+db.createObjectStore('storeName')
+addData():
+transaction = db.transaction({mode: webkitIDBTransaction.READ_WRITE})
+result = transaction.objectStore('storeName').add({x: testDate}, 'key')
+addData():
+transaction = db.transaction({mode: webkitIDBTransaction.READ_ONLY})
+result = transaction.objectStore('storeName').get('key')
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result.x.toString() == testDate.toString() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/data-corruption.html b/LayoutTests/storage/indexeddb/data-corruption.html
new file mode 100644
index 0000000..fb49fc7
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/data-corruption.html
@@ -0,0 +1,88 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="../../fast/js/resources/js-test-post-function.js"></script>
+<script src="resources/shared.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Test that data inserted into IndexedDB does not get corrupted on disk.");
+if (window.layoutTestController) 
+    layoutTestController.waitUntilDone();
+
+function test()
+{
+    result = evalAndLog("webkitIndexedDB.open('name')");
+    verifyResult(result);
+    result.onsuccess = openSuccess;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function openSuccess()
+{
+    debug("openSuccess():");
+    verifySuccessEvent(event);
+    window.db = evalAndLog("db = event.result");
+
+    result = evalAndLog("db.setVersion('new version')");
+    verifyResult(result);
+    result.onsuccess = setVersionSuccess;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function setVersionSuccess()
+{
+    debug("setVersionSuccess():");
+    verifySuccessEvent(event);
+    window.trans = evalAndLog("trans = event.result");
+    shouldBeTrue("trans !== null");
+    trans.onabort = unexpectedAbortCallback;
+    trans.oncomplete = addData;
+
+    deleteAllObjectStores(db, createObjectStore);
+}
+
+function createObjectStore()
+{
+    debug("createObjectStore():");
+    evalAndLog("db.createObjectStore('storeName')");
+}
+
+var testDate = new Date('February 24, 1955 12:00:08');
+
+function addData()
+{
+    debug("addData():");
+    var transaction = evalAndLog("transaction = db.transaction({mode: webkitIDBTransaction.READ_WRITE})");
+    var result = evalAndLog("result = transaction.objectStore('storeName').add({x: testDate}, 'key')");
+    result.onerror = unexpectedErrorCallback;
+    transaction.oncomplete = getData;
+}
+
+function getData()
+{
+    debug("addData():");
+    var transaction = evalAndLog("transaction = db.transaction({mode: webkitIDBTransaction.READ_ONLY})");
+    var result = evalAndLog("result = transaction.objectStore('storeName').get('key')");
+    result.onerror = unexpectedErrorCallback;
+    result.onsuccess = doCheck;
+}
+
+function doCheck()
+{
+    verifySuccessEvent(event);
+    shouldBeTrue("event.result.x.toString() == testDate.toString()");
+    done();
+}
+
+test();
+
+var successfullyParsed = true;
+
+</script>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 90884ac..603ab98 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,29 @@
+2011-01-22  Andrei Popescu  <andreip at google.com>
+
+        Reviewed by Jeremy Orlow.
+
+        IndexedDB corrupts data on disk
+        https://bugs.webkit.org/show_bug.cgi?id=52890
+
+        We need to store the SerializedScriptValues on disk in a BLOB column rather than TEXT.
+        Test: storage/indexeddb/data-corruption.html
+
+        * platform/sql/SQLiteStatement.cpp:
+        (WebCore::SQLiteStatement::bindBlob):
+        (WebCore::SQLiteStatement::getColumnBlobAsString):
+        (WebCore::SQLiteStatement::getColumnBlobAsVector):
+        * platform/sql/SQLiteStatement.h:
+        * storage/IDBCursorBackendImpl.cpp:
+        (WebCore::IDBCursorBackendImpl::loadCurrentRow):
+        * storage/IDBFactoryBackendImpl.cpp:
+        (WebCore::runCommands):
+        (WebCore::createTables):
+        (WebCore::createMetaDataTable):
+        (WebCore::migrateDatabase):
+        * storage/IDBObjectStoreBackendImpl.cpp:
+        (WebCore::IDBObjectStoreBackendImpl::getInternal):
+        (WebCore::putObjectStoreData):
+
 2011-01-22  Nikolas Zimmermann  <nzimmermann at rim.com>
 
         Not reviewed. Fix WinCE build.
diff --git a/Source/WebCore/platform/sql/SQLiteStatement.cpp b/Source/WebCore/platform/sql/SQLiteStatement.cpp
index af9518a..d9186dc 100644
--- a/Source/WebCore/platform/sql/SQLiteStatement.cpp
+++ b/Source/WebCore/platform/sql/SQLiteStatement.cpp
@@ -176,6 +176,20 @@ int SQLiteStatement::bindBlob(int index, const void* blob, int size)
     return sqlite3_bind_blob(m_statement, index, blob, size, SQLITE_TRANSIENT);
 }
 
+int SQLiteStatement::bindBlob(int index, const String& text)
+{
+    // String::characters() returns 0 for the empty string, which SQLite
+    // treats as a null, so we supply a non-null pointer for that case.
+    UChar anyCharacter = 0;
+    const UChar* characters;
+    if (text.isEmpty() && !text.isNull())
+        characters = &anyCharacter;
+    else
+        characters = text.characters();
+
+    return bindBlob(index, characters, text.length() * sizeof(UChar));
+}
+
 int SQLiteStatement::bindText(int index, const String& text)
 {
     ASSERT(m_isPrepared);
@@ -355,7 +369,29 @@ int64_t SQLiteStatement::getColumnInt64(int col)
         return 0;
     return sqlite3_column_int64(m_statement, col);
 }
-    
+
+String SQLiteStatement::getColumnBlobAsString(int col)
+{
+    ASSERT(col >= 0);
+
+    if (!m_statement && prepareAndStep() != SQLITE_ROW)
+        return String();
+
+    if (columnCount() <= col)
+        return String();
+
+    const void* blob = sqlite3_column_blob(m_statement, col);
+    if (!blob)
+        return String();
+
+    int size = sqlite3_column_bytes(m_statement, col);
+    if (size < 0)
+        return String();
+
+    ASSERT(!(size % sizeof(UChar)));
+    return String(static_cast<const UChar*>(blob), size / sizeof(UChar));
+}
+
 void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
 {
     ASSERT(col >= 0);
@@ -379,7 +415,7 @@ void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
     int size = sqlite3_column_bytes(m_statement, col);
     result.resize((size_t)size);
     for (int i = 0; i < size; ++i)
-        result[i] = ((const unsigned char*)blob)[i];
+        result[i] = (static_cast<const unsigned char*>(blob))[i];
 }
 
 const void* SQLiteStatement::getColumnBlob(int col, int& size)
diff --git a/Source/WebCore/platform/sql/SQLiteStatement.h b/Source/WebCore/platform/sql/SQLiteStatement.h
index fd1abfb..35dcecf 100644
--- a/Source/WebCore/platform/sql/SQLiteStatement.h
+++ b/Source/WebCore/platform/sql/SQLiteStatement.h
@@ -42,6 +42,7 @@ public:
     
     int prepare();
     int bindBlob(int index, const void* blob, int size);
+    int bindBlob(int index, const String&);
     int bindText(int index, const String&);
     int bindInt(int index, int);
     int bindInt64(int index, int64_t);
@@ -80,6 +81,7 @@ public:
     int getColumnInt(int col);
     int64_t getColumnInt64(int col);
     const void* getColumnBlob(int col, int& size);
+    String getColumnBlobAsString(int col);
     void getColumnBlobAsVector(int col, Vector<char>&);
 
     bool returnTextResults(int col, Vector<String>&);
diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.cpp b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
index d75e28d..0fe2d21 100644
--- a/Source/WebCore/storage/IDBCursorBackendImpl.cpp
+++ b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
@@ -178,7 +178,7 @@ void IDBCursorBackendImpl::loadCurrentRow()
     m_currentId = m_query->getColumnInt64(0);
     m_currentKey = IDBKey::fromQuery(*m_query, 1);
     if (m_isSerializedScriptValueCursor)
-        m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
+        m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnBlobAsString(4));
 
     m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 5);
 }
diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp
index 45cffeb..0e883cf 100644
--- a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp
+++ b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp
@@ -49,7 +49,7 @@ IDBFactoryBackendImpl::IDBFactoryBackendImpl()
     : m_transactionCoordinator(IDBTransactionCoordinator::create())
 {
 }
-
+ 
 IDBFactoryBackendImpl::~IDBFactoryBackendImpl()
 {
 }
@@ -93,11 +93,24 @@ static PassRefPtr<IDBSQLiteDatabase> openSQLiteDatabase(SecurityOrigin* security
     return sqliteDatabase.release();
 }
 
+static bool runCommands(SQLiteDatabase& sqliteDatabase, const char** commands, size_t numberOfCommands)
+{
+    SQLiteTransaction transaction(sqliteDatabase, false);
+    transaction.begin();
+    for (size_t i = 0; i < numberOfCommands; ++i) {
+        if (!sqliteDatabase.executeCommand(commands[i])) {
+            LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]);
+            return false;
+        }
+    }
+    transaction.commit();
+    return true;
+}
+
 static bool createTables(SQLiteDatabase& sqliteDatabase)
 {
     if (sqliteDatabase.tableExists("Databases"))
         return true;
-
     static const char* commands[] = {
         "CREATE TABLE Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)",
         "CREATE UNIQUE INDEX Databases_name ON Databases(name)",
@@ -117,17 +130,7 @@ static bool createTables(SQLiteDatabase& sqliteDatabase)
         "CREATE INDEX IndexData_indexId ON IndexData(indexId)",
         };
 
-    SQLiteTransaction transaction(sqliteDatabase, false);
-    transaction.begin();
-    for (size_t i = 0; i < arraysize(commands); ++i) {
-        if (!sqliteDatabase.executeCommand(commands[i])) {
-            // FIXME: We should try to recover from this situation. Maybe nuke the database and start over?
-            LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]);
-            return false;
-        }
-    }
-    transaction.commit();
-    return true;
+    return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]));
 }
 
 static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase)
@@ -137,14 +140,7 @@ static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase)
         "INSERT INTO MetaData VALUES ('version', 1)",
     };
 
-    SQLiteTransaction transaction(sqliteDatabase, false);
-    transaction.begin();
-    for (size_t i = 0; i < arraysize(commands); ++i) {
-        if (!sqliteDatabase.executeCommand(commands[i]))
-            return false;
-    }
-    transaction.commit();
-    return true;
+    return runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0]));
 }
 
 static bool getDatabaseVersion(SQLiteDatabase& sqliteDatabase, int* databaseVersion)
@@ -187,19 +183,27 @@ static bool migrateDatabase(SQLiteDatabase& sqliteDatabase)
             "UPDATE MetaData SET value = 2 WHERE name = 'version'",
         };
 
-        SQLiteTransaction transaction(sqliteDatabase, false);
-        transaction.begin();
-        for (size_t i = 0; i < arraysize(commands); ++i) {
-            if (!sqliteDatabase.executeCommand(commands[i])) {
-                LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]);
-                return false;
-            }
-        }
-        transaction.commit();
+        if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])))
+            return false;
 
         databaseVersion = 2;
     }
 
+    if (databaseVersion == 2) {
+        // We need to make the ObjectStoreData.value be a BLOB instead of TEXT.
+        static const char* commands[] = {
+            "DROP TABLE IF EXISTS ObjectStoreData", // This drops associated indices.
+            "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value BLOB NOT NULL)",
+            "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
+            "UPDATE MetaData SET value = 3 WHERE name = 'version'",
+        };
+
+        if (!runCommands(sqliteDatabase, commands, sizeof(commands) / sizeof(commands[0])))
+            return false;
+
+        databaseVersion = 3;
+    }
+
     return true;
 }
 
diff --git a/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
index 6b162ef..bd66bb1 100644
--- a/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
+++ b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
@@ -118,7 +118,7 @@ void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<
     ASSERT((key->type() == IDBKey::DateType) != query.isColumnNull(1));
     ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2));
 
-    callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(3)));
+    callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnBlobAsString(3)));
     ASSERT(query.step() != SQLResultRow);
 }
 
@@ -142,7 +142,7 @@ static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScript
     if (query.prepare() != SQLResultOk)
         return false;
     key->bindWithNulls(query, 1);
-    query.bindText(4, value->toWireString());
+    query.bindBlob(4, value->toWireString());
     if (dataRowId != IDBDatabaseBackendImpl::InvalidId)
         query.bindInt64(5, dataRowId);
     else

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list