| Index: WebCore/storage/IDBFactoryBackendImpl.cpp
|
| ===================================================================
|
| --- WebCore/storage/IDBFactoryBackendImpl.cpp (revision 73901)
|
| +++ WebCore/storage/IDBFactoryBackendImpl.cpp (working copy)
|
| @@ -35,6 +35,8 @@
|
| #include "IDBDatabaseException.h"
|
| #include "IDBSQLiteDatabase.h"
|
| #include "IDBTransactionCoordinator.h"
|
| +#include "SQLiteStatement.h"
|
| +#include "SQLiteTransaction.h"
|
| #include "SecurityOrigin.h"
|
| #include <wtf/Threading.h>
|
| #include <wtf/UnusedParam.h>
|
| @@ -93,25 +95,30 @@
|
|
|
| static bool createTables(SQLiteDatabase& sqliteDatabase)
|
| {
|
| + if (sqliteDatabase.tableExists("Databases"))
|
| + return true;
|
| +
|
| static const char* commands[] = {
|
| - "CREATE TABLE IF NOT EXISTS Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)",
|
| - "CREATE UNIQUE INDEX IF NOT EXISTS Databases_name ON Databases(name)",
|
| + "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)",
|
|
|
| - "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))",
|
| - "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_composit ON ObjectStores(databaseId, name)",
|
| + "CREATE TABLE ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))",
|
| + "CREATE UNIQUE INDEX ObjectStores_composit ON ObjectStores(databaseId, name)",
|
|
|
| - "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)",
|
| - "CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectStoreId, name)",
|
| + "CREATE TABLE Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)",
|
| + "CREATE UNIQUE INDEX Indexes_composit ON Indexes(objectStoreId, name)",
|
|
|
| - "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)",
|
| - "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
|
| + "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)",
|
| + "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
|
|
|
| - "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
|
| - "CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
|
| - "CREATE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
|
| - "CREATE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)"
|
| + "CREATE TABLE IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
|
| + "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
|
| + "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
|
| + "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?
|
| @@ -119,9 +126,83 @@
|
| return false;
|
| }
|
| }
|
| + transaction.commit();
|
| return true;
|
| }
|
|
|
| +static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase)
|
| +{
|
| + static const char* commands[] = {
|
| + "CREATE TABLE MetaData (name TEXT PRIMARY KEY, value NONE)",
|
| + "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;
|
| +}
|
| +
|
| +static bool getDatabaseVersion(SQLiteDatabase& sqliteDatabase, int* databaseVersion)
|
| +{
|
| + SQLiteStatement query(sqliteDatabase, "SELECT value FROM MetaData WHERE name = 'version'");
|
| + if (query.prepare() != SQLResultOk || query.step() != SQLResultRow)
|
| + return false;
|
| +
|
| + *databaseVersion = query.getColumnInt(0);
|
| + return query.finalize() == SQLResultOk;
|
| +}
|
| +
|
| +static bool migrateDatabase(SQLiteDatabase& sqliteDatabase)
|
| +{
|
| + if (!sqliteDatabase.tableExists("MetaData")) {
|
| + if (!createMetaDataTable(sqliteDatabase))
|
| + return false;
|
| + }
|
| +
|
| + int databaseVersion;
|
| + if (!getDatabaseVersion(sqliteDatabase, &databaseVersion))
|
| + return false;
|
| +
|
| + if (databaseVersion == 1) {
|
| + static const char* commands[] = {
|
| + "DROP TABLE IF EXISTS ObjectStoreData2",
|
| + "CREATE TABLE ObjectStoreData2 (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value TEXT NOT NULL)",
|
| + "INSERT INTO ObjectStoreData2 SELECT * FROM ObjectStoreData",
|
| + "DROP TABLE ObjectStoreData", // This depends on SQLite not enforcing referential consistency.
|
| + "ALTER TABLE ObjectStoreData2 RENAME TO ObjectStoreData",
|
| + "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
|
| + "DROP TABLE IF EXISTS IndexData2", // This depends on SQLite not enforcing referential consistency.
|
| + "CREATE TABLE IndexData2 (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate REAL, keyNumber REAL, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
|
| + "INSERT INTO IndexData2 SELECT * FROM IndexData",
|
| + "DROP TABLE IndexData",
|
| + "ALTER TABLE IndexData2 RENAME TO IndexData",
|
| + "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
|
| + "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
|
| + "CREATE INDEX IndexData_indexId ON IndexData(indexId)",
|
| + "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();
|
| +
|
| + databaseVersion = 2;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize)
|
| {
|
| String fileIdentifier = securityOrigin->databaseIdentifier();
|
| @@ -141,8 +222,9 @@
|
| else {
|
| sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this);
|
|
|
| - if (!sqliteDatabase || !createTables(sqliteDatabase->db())) {
|
| + if (!sqliteDatabase || !createTables(sqliteDatabase->db()) || !migrateDatabase(sqliteDatabase->db())) {
|
| callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
|
| + m_sqliteDatabaseMap.set(fileIdentifier, 0);
|
| return;
|
| }
|
| m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get());
|
| @@ -156,4 +238,3 @@
|
| } // namespace WebCore
|
|
|
| #endif // ENABLE(INDEXED_DATABASE)
|
| -
|
|
|