[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