diff options
Diffstat (limited to 'Source/WebCore/storage/IDBDatabaseBackendImpl.cpp')
| -rw-r--r-- | Source/WebCore/storage/IDBDatabaseBackendImpl.cpp | 179 |
1 files changed, 81 insertions, 98 deletions
diff --git a/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp index 133c5ae..94e305b 100644 --- a/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp +++ b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp @@ -30,65 +30,39 @@ #include "CrossThreadTask.h" #include "DOMStringList.h" +#include "IDBBackingStore.h" #include "IDBDatabaseException.h" #include "IDBFactoryBackendImpl.h" #include "IDBObjectStoreBackendImpl.h" -#include "IDBSQLiteDatabase.h" #include "IDBTransactionBackendImpl.h" #include "IDBTransactionCoordinator.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" namespace WebCore { -static bool extractMetaData(SQLiteDatabase& sqliteDatabase, const String& name, String& foundVersion, int64& foundId) -{ - SQLiteStatement databaseQuery(sqliteDatabase, "SELECT id, version FROM Databases WHERE name = ?"); - if (databaseQuery.prepare() != SQLResultOk) { - ASSERT_NOT_REACHED(); - return false; +class IDBDatabaseBackendImpl::PendingSetVersionCall : public RefCounted<PendingSetVersionCall> { +public: + static PassRefPtr<PendingSetVersionCall> create(const String& version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks) + { + return adoptRef(new PendingSetVersionCall(version, callbacks, databaseCallbacks)); } - databaseQuery.bindText(1, name); - if (databaseQuery.step() != SQLResultRow) - return false; - - foundId = databaseQuery.getColumnInt64(0); - foundVersion = databaseQuery.getColumnText(1); - - if (databaseQuery.step() == SQLResultRow) - ASSERT_NOT_REACHED(); - return true; -} - -static bool setMetaData(SQLiteDatabase& sqliteDatabase, const String& name, const String& version, int64_t& rowId) -{ - ASSERT(!name.isNull()); - ASSERT(!version.isNull()); - - String sql = rowId != IDBDatabaseBackendImpl::InvalidId ? "UPDATE Databases SET name = ?, version = ? WHERE id = ?" - : "INSERT INTO Databases (name, description, version) VALUES (?, '', ?)"; - SQLiteStatement query(sqliteDatabase, sql); - if (query.prepare() != SQLResultOk) { - ASSERT_NOT_REACHED(); - return false; + String version() { return m_version; } + PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; } + PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks() { return m_databaseCallbacks; } + +private: + PendingSetVersionCall(const String& version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks) + : m_version(version) + , m_callbacks(callbacks) + , m_databaseCallbacks(databaseCallbacks) + { } + String m_version; + RefPtr<IDBCallbacks> m_callbacks; + RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks; +}; - query.bindText(1, name); - query.bindText(2, version); - if (rowId != IDBDatabaseBackendImpl::InvalidId) - query.bindInt64(3, rowId); - - if (query.step() != SQLResultDone) - return false; - - if (rowId == IDBDatabaseBackendImpl::InvalidId) - rowId = sqliteDatabase.lastInsertRowID(); - - return true; -} - -IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBSQLiteDatabase* sqliteDatabase, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) - : m_sqliteDatabase(sqliteDatabase) +IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStore* backingStore, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier) + : m_backingStore(backingStore) , m_id(InvalidId) , m_name(name) , m_version("") @@ -98,9 +72,9 @@ IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBSQLiteData { ASSERT(!m_name.isNull()); - bool success = extractMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id); + bool success = m_backingStore->extractIDBDatabaseMetaData(m_name, m_version, m_id); ASSERT_UNUSED(success, success == (m_id != InvalidId)); - if (!setMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id)) + if (!m_backingStore->setIDBDatabaseMetaData(m_name, m_version, m_id, m_id == InvalidId)) ASSERT_NOT_REACHED(); // FIXME: Need better error handling. loadObjectStores(); } @@ -110,9 +84,9 @@ IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl() m_factory->removeIDBDatabaseBackend(m_identifier); } -SQLiteDatabase& IDBDatabaseBackendImpl::sqliteDatabase() const +PassRefPtr<IDBBackingStore> IDBDatabaseBackendImpl::backingStore() const { - return m_sqliteDatabase->db(); + return m_backingStore; } PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStoreNames() const @@ -132,7 +106,7 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObject return 0; } - RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), name, keyPath, autoIncrement); + RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(m_backingStore.get(), name, keyPath, autoIncrement); ASSERT(objectStore->name() == name); RefPtr<IDBDatabaseBackendImpl> database = this; @@ -149,21 +123,14 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObject void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction) { - SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)"); - if (insert.prepare() != SQLResultOk) { - transaction->abort(); - return; - } - insert.bindText(1, objectStore->name()); - insert.bindText(2, objectStore->keyPath()); - insert.bindInt(3, static_cast<int>(objectStore->autoIncrement())); - insert.bindInt64(4, database->id()); - if (insert.step() != SQLResultDone) { + int64_t objectStoreId; + + if (!database->m_backingStore->createObjectStore(objectStore->name(), objectStore->keyPath(), objectStore->autoIncrement(), database->id(), objectStoreId)) { transaction->abort(); return; } - int64_t id = database->sqliteDatabase().lastInsertRowID(); - objectStore->setId(id); + + objectStore->setId(objectStoreId); transaction->didCompleteTaskEvents(); } @@ -172,16 +139,6 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(c return m_objectStores.get(name); } -static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id) -{ - SQLiteStatement deleteQuery(db, sql); - bool ok = deleteQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. - deleteQuery.bindInt64(1, id); - ok = deleteQuery.step() == SQLResultDone; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. -} - void IDBDatabaseBackendImpl::deleteObjectStore(const String& name, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) { RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name); @@ -201,19 +158,31 @@ void IDBDatabaseBackendImpl::deleteObjectStore(const String& name, IDBTransactio void IDBDatabaseBackendImpl::deleteObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction) { - doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStore->id()); - doDelete(database->sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id()); - + database->m_backingStore->deleteObjectStore(objectStore->id()); transaction->didCompleteTaskEvents(); } -void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec) +void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, ExceptionCode& ec) { - RefPtr<IDBDatabaseBackendImpl> database = this; RefPtr<IDBCallbacks> callbacks = prpCallbacks; + RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks; + if (!m_databaseCallbacksSet.contains(databaseCallbacks)) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "Connection was closed before set version transaction was created")); + return; + } + for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) { + if (*it != databaseCallbacks) + (*it)->onVersionChange(version); + } + if (m_databaseCallbacksSet.size() > 1) { + callbacks->onBlocked(); + RefPtr<PendingSetVersionCall> pendingSetVersionCall = PendingSetVersionCall::create(version, callbacks, databaseCallbacks); + m_pendingSetVersionCalls.append(pendingSetVersionCall); + return; + } + RefPtr<DOMStringList> objectStoreNames = DOMStringList::create(); + RefPtr<IDBDatabaseBackendImpl> database = this; RefPtr<IDBTransactionBackendInterface> transaction = IDBTransactionBackendImpl::create(objectStoreNames.get(), IDBTransaction::VERSION_CHANGE, this); if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::setVersionInternal, database, version, callbacks, transaction), createCallbackTask(&IDBDatabaseBackendImpl::resetVersion, database, m_version))) { @@ -225,7 +194,7 @@ void IDBDatabaseBackendImpl::setVersionInternal(ScriptExecutionContext*, PassRef { int64_t databaseId = database->id(); database->m_version = version; - if (!setMetaData(database->m_sqliteDatabase->db(), database->m_name, database->m_version, databaseId)) { + if (!database->m_backingStore->setIDBDatabaseMetaData(database->m_name, database->m_version, databaseId, databaseId == InvalidId)) { // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.")); transaction->abort(); @@ -247,29 +216,43 @@ PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(D return IDBTransactionBackendImpl::create(objectStoreNames, mode, this); } -void IDBDatabaseBackendImpl::close() +void IDBDatabaseBackendImpl::open(PassRefPtr<IDBDatabaseCallbacks> callbacks) { - // FIXME: Implement. + m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(callbacks)); } -void IDBDatabaseBackendImpl::loadObjectStores() +void IDBDatabaseBackendImpl::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks) { - SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?"); - bool ok = objectStoresQuery.prepare() == SQLResultOk; - ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? - - objectStoresQuery.bindInt64(1, m_id); - - while (objectStoresQuery.step() == SQLResultRow) { - int64_t id = objectStoresQuery.getColumnInt64(0); - String name = objectStoresQuery.getColumnText(1); - String keyPath = objectStoresQuery.getColumnText(2); - bool autoIncrement = !!objectStoresQuery.getColumnInt(3); + RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks; + ASSERT(m_databaseCallbacksSet.contains(callbacks)); + m_databaseCallbacksSet.remove(callbacks); + if (m_databaseCallbacksSet.size() > 1) + return; - m_objectStores.set(name, IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), id, name, keyPath, autoIncrement)); + while (!m_pendingSetVersionCalls.isEmpty()) { + ExceptionCode ec = 0; + RefPtr<PendingSetVersionCall> pendingSetVersionCall = m_pendingSetVersionCalls.takeFirst(); + setVersion(pendingSetVersionCall->version(), pendingSetVersionCall->callbacks(), pendingSetVersionCall->databaseCallbacks(), ec); + ASSERT(!ec); } } +void IDBDatabaseBackendImpl::loadObjectStores() +{ + Vector<int64_t> ids; + Vector<String> names; + Vector<String> keyPaths; + Vector<bool> autoIncrementFlags; + m_backingStore->getObjectStores(m_id, ids, names, keyPaths, autoIncrementFlags); + + ASSERT(names.size() == ids.size()); + ASSERT(keyPaths.size() == ids.size()); + ASSERT(autoIncrementFlags.size() == ids.size()); + + for (size_t i = 0; i < ids.size(); i++) + m_objectStores.set(names[i], IDBObjectStoreBackendImpl::create(m_backingStore.get(), ids[i], names[i], keyPaths[i], autoIncrementFlags[i])); +} + void IDBDatabaseBackendImpl::removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore) { ASSERT(database->m_objectStores.contains(objectStore->name())); |
