summaryrefslogtreecommitdiffstats
path: root/WebCore/storage
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/storage')
-rw-r--r--WebCore/storage/AbstractDatabase.cpp479
-rw-r--r--WebCore/storage/AbstractDatabase.h129
-rw-r--r--WebCore/storage/ChangeVersionWrapper.cpp9
-rw-r--r--WebCore/storage/ChangeVersionWrapper.h3
-rw-r--r--WebCore/storage/Database.cpp564
-rw-r--r--WebCore/storage/Database.h139
-rw-r--r--WebCore/storage/Database.idl3
-rw-r--r--WebCore/storage/DatabaseAuthorizer.cpp70
-rw-r--r--WebCore/storage/DatabaseAuthorizer.h17
-rw-r--r--WebCore/storage/DatabaseCallback.h55
-rw-r--r--WebCore/storage/DatabaseCallback.idl37
-rw-r--r--WebCore/storage/DatabaseDetails.h13
-rw-r--r--WebCore/storage/DatabaseSync.cpp188
-rw-r--r--WebCore/storage/DatabaseSync.h73
-rw-r--r--WebCore/storage/DatabaseSync.idl44
-rw-r--r--WebCore/storage/DatabaseTask.cpp39
-rw-r--r--WebCore/storage/DatabaseTask.h29
-rw-r--r--WebCore/storage/DatabaseThread.cpp4
-rw-r--r--WebCore/storage/DatabaseTracker.cpp726
-rw-r--r--WebCore/storage/DatabaseTracker.h72
-rw-r--r--WebCore/storage/IDBAny.cpp139
-rw-r--r--WebCore/storage/IDBAny.h103
-rw-r--r--WebCore/storage/IDBAny.idl34
-rw-r--r--WebCore/storage/IDBCallbacks.h61
-rw-r--r--WebCore/storage/IDBDatabase.h66
-rw-r--r--WebCore/storage/IDBDatabaseError.h14
-rw-r--r--WebCore/storage/IDBDatabaseError.idl4
-rw-r--r--WebCore/storage/IDBDatabaseException.h22
-rw-r--r--WebCore/storage/IDBDatabaseException.idl5
-rw-r--r--WebCore/storage/IDBDatabaseImpl.cpp88
-rw-r--r--WebCore/storage/IDBDatabaseImpl.h71
-rw-r--r--WebCore/storage/IDBDatabaseRequest.cpp73
-rw-r--r--WebCore/storage/IDBDatabaseRequest.h72
-rw-r--r--WebCore/storage/IDBDatabaseRequest.idl45
-rw-r--r--WebCore/storage/IDBErrorEvent.cpp58
-rw-r--r--WebCore/storage/IDBErrorEvent.h66
-rw-r--r--WebCore/storage/IDBErrorEvent.idl37
-rw-r--r--WebCore/storage/IDBEvent.cpp55
-rw-r--r--WebCore/storage/IDBEvent.h59
-rw-r--r--WebCore/storage/IDBEvent.idl36
-rw-r--r--WebCore/storage/IDBIndex.h50
-rw-r--r--WebCore/storage/IDBIndexImpl.cpp46
-rw-r--r--WebCore/storage/IDBIndexImpl.h60
-rw-r--r--WebCore/storage/IDBIndexRequest.cpp44
-rw-r--r--WebCore/storage/IDBIndexRequest.h62
-rw-r--r--WebCore/storage/IDBIndexRequest.idl38
-rw-r--r--WebCore/storage/IDBKey.cpp58
-rw-r--r--WebCore/storage/IDBKey.h88
-rw-r--r--WebCore/storage/IDBKey.idl34
-rw-r--r--WebCore/storage/IDBKeyRange.cpp67
-rw-r--r--WebCore/storage/IDBKeyRange.h75
-rw-r--r--WebCore/storage/IDBKeyRange.idl48
-rw-r--r--WebCore/storage/IDBKeyTree.h153
-rw-r--r--WebCore/storage/IDBObjectStore.h64
-rwxr-xr-xWebCore/storage/IDBObjectStoreImpl.cpp136
-rw-r--r--WebCore/storage/IDBObjectStoreImpl.h77
-rw-r--r--WebCore/storage/IDBObjectStoreRequest.cpp113
-rw-r--r--WebCore/storage/IDBObjectStoreRequest.h78
-rw-r--r--WebCore/storage/IDBObjectStoreRequest.idl48
-rw-r--r--WebCore/storage/IDBRequest.cpp138
-rw-r--r--WebCore/storage/IDBRequest.h80
-rw-r--r--WebCore/storage/IDBRequest.idl20
-rw-r--r--WebCore/storage/IDBSuccessEvent.cpp61
-rw-r--r--WebCore/storage/IDBSuccessEvent.h62
-rw-r--r--WebCore/storage/IDBSuccessEvent.idl36
-rw-r--r--WebCore/storage/IndexedDatabase.cpp49
-rw-r--r--WebCore/storage/IndexedDatabase.h61
-rw-r--r--WebCore/storage/IndexedDatabaseImpl.cpp71
-rw-r--r--WebCore/storage/IndexedDatabaseImpl.h61
-rw-r--r--WebCore/storage/IndexedDatabaseRequest.cpp30
-rw-r--r--WebCore/storage/IndexedDatabaseRequest.h16
-rw-r--r--WebCore/storage/IndexedDatabaseRequest.idl8
-rw-r--r--WebCore/storage/LocalStorageTask.cpp5
-rw-r--r--WebCore/storage/LocalStorageTask.h3
-rw-r--r--WebCore/storage/OriginQuotaManager.cpp18
-rw-r--r--WebCore/storage/OriginQuotaManager.h5
-rw-r--r--WebCore/storage/OriginUsageRecord.cpp6
-rw-r--r--WebCore/storage/SQLError.h13
-rw-r--r--WebCore/storage/SQLError.idl13
-rw-r--r--WebCore/storage/SQLException.h72
-rw-r--r--WebCore/storage/SQLException.idl51
-rw-r--r--WebCore/storage/SQLResultSet.cpp3
-rw-r--r--WebCore/storage/SQLResultSet.h5
-rw-r--r--WebCore/storage/SQLResultSet.idl9
-rw-r--r--WebCore/storage/SQLResultSetRowList.idl3
-rw-r--r--WebCore/storage/SQLStatement.cpp28
-rw-r--r--WebCore/storage/SQLStatement.h15
-rw-r--r--WebCore/storage/SQLStatementCallback.h5
-rw-r--r--WebCore/storage/SQLStatementCallback.idl36
-rw-r--r--WebCore/storage/SQLStatementErrorCallback.h5
-rw-r--r--WebCore/storage/SQLStatementErrorCallback.idl36
-rw-r--r--WebCore/storage/SQLStatementSync.cpp127
-rw-r--r--WebCore/storage/SQLStatementSync.h63
-rw-r--r--WebCore/storage/SQLTransaction.cpp98
-rw-r--r--WebCore/storage/SQLTransaction.h16
-rw-r--r--WebCore/storage/SQLTransaction.idl3
-rw-r--r--WebCore/storage/SQLTransactionCallback.h6
-rw-r--r--WebCore/storage/SQLTransactionCallback.idl36
-rw-r--r--WebCore/storage/SQLTransactionClient.cpp28
-rw-r--r--WebCore/storage/SQLTransactionClient.h21
-rw-r--r--WebCore/storage/SQLTransactionCoordinator.cpp4
-rw-r--r--WebCore/storage/SQLTransactionCoordinator.h1
-rw-r--r--WebCore/storage/SQLTransactionErrorCallback.h15
-rw-r--r--WebCore/storage/SQLTransactionErrorCallback.idl36
-rw-r--r--WebCore/storage/SQLTransactionSync.cpp206
-rw-r--r--WebCore/storage/SQLTransactionSync.h84
-rw-r--r--WebCore/storage/SQLTransactionSync.idl40
-rw-r--r--WebCore/storage/SQLTransactionSyncCallback.h54
-rw-r--r--WebCore/storage/SQLTransactionSyncCallback.idl38
-rw-r--r--WebCore/storage/StorageAreaImpl.cpp22
-rw-r--r--WebCore/storage/StorageAreaSync.cpp143
-rw-r--r--WebCore/storage/StorageAreaSync.h16
-rw-r--r--WebCore/storage/StorageEvent.cpp16
-rw-r--r--WebCore/storage/StorageEvent.h13
-rw-r--r--WebCore/storage/StorageEvent.idl6
-rw-r--r--WebCore/storage/StorageEventDispatcher.cpp16
-rw-r--r--WebCore/storage/StorageNamespace.cpp4
-rw-r--r--WebCore/storage/StorageNamespace.h2
-rw-r--r--WebCore/storage/StorageNamespaceImpl.cpp10
-rw-r--r--WebCore/storage/StorageNamespaceImpl.h2
-rw-r--r--WebCore/storage/StorageSyncManager.cpp9
-rw-r--r--WebCore/storage/StorageSyncManager.h1
-rw-r--r--WebCore/storage/chromium/DatabaseObserver.h19
-rw-r--r--WebCore/storage/chromium/DatabaseTrackerChromium.cpp38
-rw-r--r--WebCore/storage/chromium/IndexedDatabase.cpp45
-rw-r--r--WebCore/storage/chromium/QuotaTracker.cpp5
-rw-r--r--WebCore/storage/chromium/QuotaTracker.h6
-rw-r--r--WebCore/storage/chromium/SQLTransactionClientChromium.cpp34
128 files changed, 6223 insertions, 1224 deletions
diff --git a/WebCore/storage/AbstractDatabase.cpp b/WebCore/storage/AbstractDatabase.cpp
new file mode 100644
index 0000000..bcc5d06
--- /dev/null
+++ b/WebCore/storage/AbstractDatabase.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AbstractDatabase.h"
+
+#if ENABLE(DATABASE)
+#include "DatabaseAuthorizer.h"
+#include "DatabaseTracker.h"
+#include "Logging.h"
+#include "SQLiteStatement.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
+{
+ SQLiteStatement statement(db, query);
+ int result = statement.prepare();
+
+ if (result != SQLResultOk) {
+ LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
+ return false;
+ }
+
+ result = statement.step();
+ if (result == SQLResultRow) {
+ resultString = statement.getColumnText(0);
+ return true;
+ }
+ if (result == SQLResultDone) {
+ resultString = String();
+ return true;
+ }
+
+ LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
+ return false;
+}
+
+static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
+{
+ SQLiteStatement statement(db, query);
+ int result = statement.prepare();
+
+ if (result != SQLResultOk) {
+ LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
+ return false;
+ }
+
+ statement.bindText(1, value);
+
+ result = statement.step();
+ if (result != SQLResultDone) {
+ LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
+ return false;
+ }
+
+ return true;
+}
+
+// FIXME: move all guid-related functions to a DatabaseVersionTracker class.
+static Mutex& guidMutex()
+{
+ // Note: We don't have to use AtomicallyInitializedStatic here because
+ // this function is called once in the constructor on the main thread
+ // before any other threads that call this function are used.
+ DEFINE_STATIC_LOCAL(Mutex, mutex, ());
+ return mutex;
+}
+
+typedef HashMap<int, String> GuidVersionMap;
+static GuidVersionMap& guidToVersionMap()
+{
+ DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
+ 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.threadsafeCopy());
+}
+
+typedef HashMap<int, HashSet<AbstractDatabase*>*> GuidDatabaseMap;
+static GuidDatabaseMap& guidToDatabaseMap()
+{
+ DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
+ return map;
+}
+
+static int guidForOriginAndName(const String& origin, const String& name)
+{
+ String stringID = origin + "/" + name;
+
+ // Note: We don't have to use AtomicallyInitializedStatic here because
+ // this function is called once in the constructor on the main thread
+ // before any other threads that call this function are used.
+ DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ());
+ MutexLocker locker(stringIdentifierMutex);
+ typedef HashMap<String, int> IDGuidMap;
+ DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
+ int guid = stringIdentifierToGUIDMap.get(stringID);
+ if (!guid) {
+ static int currentNewGUID = 1;
+ guid = currentNewGUID++;
+ stringIdentifierToGUIDMap.set(stringID, guid);
+ }
+
+ return guid;
+}
+
+static bool isDatabaseAvailable = true;
+
+bool AbstractDatabase::isAvailable()
+{
+ return isDatabaseAvailable;
+}
+
+void AbstractDatabase::setIsAvailable(bool available)
+{
+ isDatabaseAvailable = available;
+}
+
+// static
+const String& AbstractDatabase::databaseInfoTableName()
+{
+ DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
+ return name;
+}
+
+AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize)
+ : m_scriptExecutionContext(context)
+ , m_name(name.crossThreadString())
+ , m_expectedVersion(expectedVersion.crossThreadString())
+ , m_displayName(displayName.crossThreadString())
+ , m_estimatedSize(estimatedSize)
+ , m_guid(0)
+ , m_opened(false)
+ , m_new(false)
+{
+ ASSERT(context->isContextThread());
+ m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
+
+ m_databaseAuthorizer = DatabaseAuthorizer::create(databaseInfoTableName());
+
+ if (m_name.isNull())
+ m_name = "";
+
+ m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
+ {
+ MutexLocker locker(guidMutex());
+
+ HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid);
+ if (!hashSet) {
+ hashSet = new HashSet<AbstractDatabase*>;
+ guidToDatabaseMap().set(m_guid, hashSet);
+ }
+
+ hashSet->add(this);
+ }
+
+ m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
+ DatabaseTracker::tracker().addOpenDatabase(this);
+}
+
+AbstractDatabase::~AbstractDatabase()
+{
+}
+
+void AbstractDatabase::closeDatabase()
+{
+ if (!m_opened)
+ return;
+
+ m_sqliteDatabase.close();
+ m_opened = false;
+ {
+ MutexLocker locker(guidMutex());
+
+ HashSet<AbstractDatabase*>* 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);
+ }
+ }
+}
+
+String AbstractDatabase::version() const
+{
+ MutexLocker locker(guidMutex());
+ return guidToVersionMap().get(m_guid).threadsafeCopy();
+}
+
+static const int maxSqliteBusyWaitTime = 30000;
+bool AbstractDatabase::performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec)
+{
+ if (!m_sqliteDatabase.open(m_filename, true)) {
+ LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data());
+ ec = INVALID_STATE_ERR;
+ return false;
+ }
+ if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
+ LOG_ERROR("Unable to turn on incremental auto-vacuum for database %s", m_filename.ascii().data());
+
+ ASSERT(m_databaseAuthorizer);
+ m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
+ m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
+
+ String currentVersion;
+ {
+ MutexLocker locker(guidMutex());
+
+ GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
+ if (entry != guidToVersionMap().end()) {
+ // 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 {
+ LOG(StorageAPI, "No cached version for guid %i", m_guid);
+
+ if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
+ m_new = true;
+
+ if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
+ LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
+ ec = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
+ return false;
+ }
+ }
+
+ if (!getVersionFromDatabase(currentVersion)) {
+ LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
+ ec = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
+ return false;
+ }
+ if (currentVersion.length()) {
+ LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
+ } else if (!m_new || shouldSetVersionInNewDatabase) {
+ LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
+ if (!setVersionInDatabase(m_expectedVersion)) {
+ LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
+ ec = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
+ return false;
+ }
+ currentVersion = m_expectedVersion;
+ }
+
+ updateGuidVersionMap(m_guid, currentVersion);
+ }
+ }
+
+ if (currentVersion.isNull()) {
+ LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
+ currentVersion = "";
+ }
+
+ // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
+ // If the expected version is the empty string, then we always return with whatever version of the database we have.
+ if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
+ LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
+ databaseDebugName().ascii().data(), currentVersion.ascii().data());
+ ec = INVALID_STATE_ERR;
+ // Close the handle to the database file.
+ m_sqliteDatabase.close();
+ return false;
+ }
+
+ m_opened = true;
+
+ return true;
+}
+
+ScriptExecutionContext* AbstractDatabase::scriptExecutionContext() const
+{
+ return m_scriptExecutionContext.get();
+}
+
+SecurityOrigin* AbstractDatabase::securityOrigin() const
+{
+ return m_contextThreadSecurityOrigin.get();
+}
+
+String AbstractDatabase::stringIdentifier() const
+{
+ // Return a deep copy for ref counting thread safety
+ return m_name.threadsafeCopy();
+}
+
+String AbstractDatabase::displayName() const
+{
+ // Return a deep copy for ref counting thread safety
+ return m_displayName.threadsafeCopy();
+}
+
+unsigned long AbstractDatabase::estimatedSize() const
+{
+ return m_estimatedSize;
+}
+
+String AbstractDatabase::fileName() const
+{
+ // Return a deep copy for ref counting thread safety
+ return m_filename.threadsafeCopy();
+}
+
+// static
+const String& AbstractDatabase::databaseVersionKey()
+{
+ DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey"));
+ return key;
+}
+
+bool AbstractDatabase::getVersionFromDatabase(String& version)
+{
+ DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';"));
+
+ m_databaseAuthorizer->disable();
+
+ bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
+ if (!result)
+ LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
+
+ m_databaseAuthorizer->enable();
+
+ return result;
+}
+
+bool AbstractDatabase::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();
+
+ bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
+ if (!result)
+ LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
+
+ m_databaseAuthorizer->enable();
+
+ return result;
+}
+
+bool AbstractDatabase::versionMatchesExpected() const
+{
+ if (!m_expectedVersion.isEmpty()) {
+ MutexLocker locker(guidMutex());
+ return m_expectedVersion == guidToVersionMap().get(m_guid);
+ }
+
+ return true;
+}
+
+void AbstractDatabase::setExpectedVersion(const String& version)
+{
+ m_expectedVersion = version.threadsafeCopy();
+ // Update the in memory database version map.
+ MutexLocker locker(guidMutex());
+ updateGuidVersionMap(m_guid, version);
+}
+
+void AbstractDatabase::disableAuthorizer()
+{
+ ASSERT(m_databaseAuthorizer);
+ m_databaseAuthorizer->disable();
+}
+
+void AbstractDatabase::enableAuthorizer()
+{
+ ASSERT(m_databaseAuthorizer);
+ m_databaseAuthorizer->enable();
+}
+
+void AbstractDatabase::setAuthorizerReadOnly()
+{
+ ASSERT(m_databaseAuthorizer);
+ m_databaseAuthorizer->setReadOnly();
+}
+
+bool AbstractDatabase::lastActionChangedDatabase()
+{
+ ASSERT(m_databaseAuthorizer);
+ return m_databaseAuthorizer->lastActionChangedDatabase();
+}
+
+bool AbstractDatabase::lastActionWasInsert()
+{
+ ASSERT(m_databaseAuthorizer);
+ return m_databaseAuthorizer->lastActionWasInsert();
+}
+
+void AbstractDatabase::resetDeletes()
+{
+ ASSERT(m_databaseAuthorizer);
+ m_databaseAuthorizer->resetDeletes();
+}
+
+bool AbstractDatabase::hadDeletes()
+{
+ ASSERT(m_databaseAuthorizer);
+ return m_databaseAuthorizer->hadDeletes();
+}
+
+void AbstractDatabase::resetAuthorizer()
+{
+ if (m_databaseAuthorizer)
+ m_databaseAuthorizer->reset();
+}
+
+unsigned long long AbstractDatabase::maximumSize() const
+{
+ return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
+}
+
+void AbstractDatabase::incrementalVacuumIfNeeded()
+{
+ int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
+ int64_t totalSize = m_sqliteDatabase.totalSize();
+ if (totalSize <= 10 * freeSpaceSize)
+ m_sqliteDatabase.runIncrementalVacuumCommand();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/AbstractDatabase.h b/WebCore/storage/AbstractDatabase.h
new file mode 100644
index 0000000..e302909
--- /dev/null
+++ b/WebCore/storage/AbstractDatabase.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AbstractDatabase_h
+#define AbstractDatabase_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include "SQLiteDatabase.h"
+#include <wtf/Forward.h>
+#include <wtf/ThreadSafeShared.h>
+#ifndef NDEBUG
+#include "SecurityOrigin.h"
+#endif
+
+namespace WebCore {
+
+class DatabaseAuthorizer;
+class ScriptExecutionContext;
+class SecurityOrigin;
+
+class AbstractDatabase : public ThreadSafeShared<AbstractDatabase> {
+public:
+ static bool isAvailable();
+ static void setIsAvailable(bool available);
+
+ virtual ~AbstractDatabase();
+
+ virtual String version() const;
+
+ bool opened() const { return m_opened; }
+ bool isNew() const { return m_new; }
+
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+ virtual SecurityOrigin* securityOrigin() const;
+ virtual String stringIdentifier() const;
+ virtual String displayName() const;
+ virtual unsigned long estimatedSize() const;
+ virtual String fileName() const;
+ SQLiteDatabase& sqliteDatabase() { return m_sqliteDatabase; }
+
+ unsigned long long maximumSize() const;
+ void incrementalVacuumIfNeeded();
+
+ // FIXME: move all version-related methods to a DatabaseVersionTracker class
+ bool versionMatchesExpected() const;
+ void setExpectedVersion(const String& version);
+ bool getVersionFromDatabase(String& version);
+ bool setVersionInDatabase(const String& version);
+
+ void disableAuthorizer();
+ void enableAuthorizer();
+ void setAuthorizerReadOnly();
+ bool lastActionChangedDatabase();
+ bool lastActionWasInsert();
+ void resetDeletes();
+ bool hadDeletes();
+ void resetAuthorizer();
+
+ virtual void markAsDeletedAndClose() = 0;
+ virtual void closeImmediately() = 0;
+
+protected:
+ AbstractDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize);
+
+ void closeDatabase();
+
+ virtual bool performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec);
+
+ static const String& databaseInfoTableName();
+
+ RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
+ RefPtr<SecurityOrigin> m_contextThreadSecurityOrigin;
+
+ String m_name;
+ String m_expectedVersion;
+ String m_displayName;
+ unsigned long m_estimatedSize;
+ String m_filename;
+
+#ifndef NDEBUG
+ String databaseDebugName() const { return m_contextThreadSecurityOrigin->toString() + "::" + m_name; }
+#endif
+
+private:
+ static const String& databaseVersionKey();
+
+ int m_guid;
+ bool m_opened;
+ bool m_new;
+
+ SQLiteDatabase m_sqliteDatabase;
+
+ RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // AbstractDatabase_h
diff --git a/WebCore/storage/ChangeVersionWrapper.cpp b/WebCore/storage/ChangeVersionWrapper.cpp
index 17a9407..17be716 100644
--- a/WebCore/storage/ChangeVersionWrapper.cpp
+++ b/WebCore/storage/ChangeVersionWrapper.cpp
@@ -30,6 +30,9 @@
#if ENABLE(DATABASE)
#include "Database.h"
+#include "SQLError.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
namespace WebCore {
@@ -47,13 +50,13 @@ bool ChangeVersionWrapper::performPreflight(SQLTransaction* transaction)
if (!transaction->database()->getVersionFromDatabase(actualVersion)) {
LOG_ERROR("Unable to retrieve actual current version from database");
- m_sqlError = SQLError::create(0, "unable to verify current version of database");
+ m_sqlError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to verify current version of database");
return false;
}
if (actualVersion != m_oldVersion) {
LOG_ERROR("Old version doesn't match actual version");
- m_sqlError = SQLError::create(2, "current version of the database and `oldVersion` argument do not match");
+ m_sqlError = SQLError::create(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match");
return false;
}
@@ -66,7 +69,7 @@ bool ChangeVersionWrapper::performPostflight(SQLTransaction* transaction)
if (!transaction->database()->setVersionInDatabase(m_newVersion)) {
LOG_ERROR("Unable to set new version in database");
- m_sqlError = SQLError::create(0, "unable to set new version in database");
+ m_sqlError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to set new version in database");
return false;
}
diff --git a/WebCore/storage/ChangeVersionWrapper.h b/WebCore/storage/ChangeVersionWrapper.h
index b14fe55..86cc182 100644
--- a/WebCore/storage/ChangeVersionWrapper.h
+++ b/WebCore/storage/ChangeVersionWrapper.h
@@ -32,9 +32,12 @@
#include "PlatformString.h"
#include "SQLTransaction.h"
+#include <wtf/Forward.h>
namespace WebCore {
+class SQLError;
+
class ChangeVersionWrapper : public SQLTransactionWrapper {
public:
static PassRefPtr<ChangeVersionWrapper> create(const String& oldVersion, const String& newVersion) { return adoptRef(new ChangeVersionWrapper(oldVersion, newVersion)); }
diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp
index 2130631..69f5036 100644
--- a/WebCore/storage/Database.cpp
+++ b/WebCore/storage/Database.cpp
@@ -29,32 +29,31 @@
#include "config.h"
#include "Database.h"
-#include <wtf/StdLibExtras.h>
-
#if ENABLE(DATABASE)
#include "ChangeVersionWrapper.h"
-#include "CString.h"
-#include "DatabaseAuthorizer.h"
+#include "DatabaseCallback.h"
#include "DatabaseTask.h"
#include "DatabaseThread.h"
#include "DatabaseTracker.h"
#include "Document.h"
-#include "ExceptionCode.h"
-#include "Frame.h"
#include "InspectorController.h"
#include "Logging.h"
#include "NotImplemented.h"
#include "Page.h"
-#include "OriginQuotaManager.h"
-#include "ScriptController.h"
-#include "SQLiteDatabase.h"
-#include "SQLiteFileSystem.h"
-#include "SQLiteStatement.h"
-#include "SQLResultSet.h"
+#include "SQLTransactionCallback.h"
#include "SQLTransactionClient.h"
#include "SQLTransactionCoordinator.h"
-
-#endif // ENABLE(DATABASE)
+#include "SQLTransactionErrorCallback.h"
+#include "SQLiteStatement.h"
+#include "ScriptController.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "VoidCallback.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/StdLibExtras.h>
#if USE(JSC)
#include "JSDOMWindow.h"
@@ -62,89 +61,43 @@
namespace WebCore {
-// If we sleep for more the 30 seconds while blocked on SQLITE_BUSY, give up.
-static const int maxSqliteBusyWaitTime = 30000;
-
-const String& Database::databaseInfoTableName()
-{
- DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
- return name;
-}
-
-#if ENABLE(DATABASE)
-
-static bool isDatabaseAvailable = true;
-
-void Database::setIsAvailable(bool available)
-{
- isDatabaseAvailable = available;
-}
-
-bool Database::isAvailable()
-{
- return isDatabaseAvailable;
-}
-
-static Mutex& guidMutex()
-{
- // Note: We don't have to use AtomicallyInitializedStatic here because
- // this function is called once in the constructor on the main thread
- // before any other threads that call this function are used.
- DEFINE_STATIC_LOCAL(Mutex, mutex, ());
- return mutex;
-}
-
-typedef HashMap<int, String> GuidVersionMap;
-static GuidVersionMap& guidToVersionMap()
-{
- DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
- 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.threadsafeCopy());
-}
+class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> creationCallback)
+ {
+ return new DatabaseCreationCallbackTask(database, creationCallback);
+ }
-typedef HashMap<int, HashSet<Database*>*> GuidDatabaseMap;
-static GuidDatabaseMap& guidToDatabaseMap()
-{
- DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
- return map;
-}
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ m_creationCallback->handleEvent(context, m_database.get());
+ }
-static const String& databaseVersionKey()
-{
- DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey"));
- return key;
-}
+private:
+ DatabaseCreationCallbackTask(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> callback)
+ : m_database(database)
+ , m_creationCallback(callback)
+ {
+ }
-static int guidForOriginAndName(const String& origin, const String& name);
+ RefPtr<Database> m_database;
+ RefPtr<DatabaseCallback> m_creationCallback;
+};
-PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
+PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name,
+ const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback,
+ ExceptionCode& e)
{
if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
- // FIXME: There should be an exception raised here in addition to returning a null Database object. The question has been raised with the WHATWG.
LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
return 0;
}
RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize));
- if (!database->openAndVerifyVersion(e)) {
+ if (!database->openAndVerifyVersion(!creationCallback, e)) {
LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
- context->removeOpenDatabase(database.get());
DatabaseTracker::tracker().removeOpenDatabase(database.get());
return 0;
}
@@ -160,84 +113,82 @@ PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, con
}
#endif
+ // If it's a new database and a creation callback was provided, reset the expected
+ // version to "" and schedule the creation callback. Because of some subtle String
+ // implementation issues, we have to reset m_expectedVersion here instead of doing
+ // it inside performOpenAndVerify() which is run on the DB thread.
+ if (database->isNew() && creationCallback.get()) {
+ database->m_expectedVersion = "";
+ LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get());
+ database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database, creationCallback));
+ }
+
return database;
}
Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
- : m_transactionInProgress(false)
+ : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize)
+ , m_transactionInProgress(false)
, m_isTransactionQueueEnabled(true)
- , m_scriptExecutionContext(context)
- , m_name(name.crossThreadString())
- , m_guid(0)
- , m_expectedVersion(expectedVersion.crossThreadString())
- , m_displayName(displayName.crossThreadString())
- , m_estimatedSize(estimatedSize)
, m_deleted(false)
- , m_stopped(false)
- , m_opened(false)
{
- ASSERT(m_scriptExecutionContext.get());
- m_mainThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
- m_databaseThreadSecurityOrigin = m_mainThreadSecurityOrigin->threadsafeCopy();
- if (m_name.isNull())
- m_name = "";
+ m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->threadsafeCopy();
ScriptController::initializeThreading();
-
- m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
-
- {
- MutexLocker locker(guidMutex());
-
- HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
- if (!hashSet) {
- hashSet = new HashSet<Database*>;
- guidToDatabaseMap().set(m_guid, hashSet);
- }
-
- hashSet->add(this);
- }
-
ASSERT(m_scriptExecutionContext->databaseThread());
- m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
-
- DatabaseTracker::tracker().addOpenDatabase(this);
- context->addOpenDatabase(this);
}
class DerefContextTask : public ScriptExecutionContext::Task {
public:
- static PassOwnPtr<DerefContextTask> create()
+ static PassOwnPtr<DerefContextTask> create(PassRefPtr<ScriptExecutionContext> context)
{
- return new DerefContextTask();
+ return new DerefContextTask(context);
}
virtual void performTask(ScriptExecutionContext* context)
{
- context->deref();
+ ASSERT_UNUSED(context, context == m_context);
+ m_context.clear();
}
virtual bool isCleanupTask() const { return true; }
+
+private:
+ DerefContextTask(PassRefPtr<ScriptExecutionContext> context)
+ : m_context(context)
+ {
+ }
+
+ RefPtr<ScriptExecutionContext> m_context;
};
Database::~Database()
{
// The reference to the ScriptExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing.
if (!m_scriptExecutionContext->isContextThread()) {
- m_scriptExecutionContext->postTask(DerefContextTask::create());
- m_scriptExecutionContext.release().releaseRef();
+ // Grab a pointer to the script execution here because we're releasing it when we pass it to
+ // DerefContextTask::create.
+ ScriptExecutionContext* scriptExecutionContext = m_scriptExecutionContext.get();
+
+ scriptExecutionContext->postTask(DerefContextTask::create(m_scriptExecutionContext.release()));
}
}
-bool Database::openAndVerifyVersion(ExceptionCode& e)
+String Database::version() const
+{
+ if (m_deleted)
+ return String();
+ return AbstractDatabase::version();
+}
+
+bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode& e)
{
if (!m_scriptExecutionContext->databaseThread())
return false;
- m_databaseAuthorizer = DatabaseAuthorizer::create();
bool success = false;
DatabaseTaskSynchronizer synchronizer;
- OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success);
+ OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, e, success);
m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
@@ -245,93 +196,6 @@ bool Database::openAndVerifyVersion(ExceptionCode& e)
return success;
}
-
-static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
-{
- SQLiteStatement statement(db, query);
- int result = statement.prepare();
-
- if (result != SQLResultOk) {
- LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
- return false;
- }
-
- result = statement.step();
- if (result == SQLResultRow) {
- resultString = statement.getColumnText(0);
- return true;
- } else if (result == SQLResultDone) {
- resultString = String();
- return true;
- } else {
- LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
- return false;
- }
-}
-
-bool Database::getVersionFromDatabase(String& version)
-{
- DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';"));
-
- m_databaseAuthorizer->disable();
-
- bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
- if (!result)
- LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
-
- m_databaseAuthorizer->enable();
-
- return result;
-}
-
-static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
-{
- SQLiteStatement statement(db, query);
- int result = statement.prepare();
-
- if (result != SQLResultOk) {
- LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
- return false;
- }
-
- statement.bindText(1, value);
-
- result = statement.step();
- if (result != SQLResultDone) {
- LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
- return false;
- }
-
- return true;
-}
-
-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();
-
- bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
- if (!result)
- LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
-
- m_databaseAuthorizer->enable();
-
- return result;
-}
-
-bool Database::versionMatchesExpected() const
-{
- if (!m_expectedVersion.isEmpty()) {
- MutexLocker locker(guidMutex());
- return m_expectedVersion == guidToVersionMap().get(m_guid);
- }
-
- return true;
-}
-
void Database::markAsDeletedAndClose()
{
if (m_deleted || !m_scriptExecutionContext->databaseThread())
@@ -345,8 +209,6 @@ void Database::markAsDeletedAndClose()
return;
}
- m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
-
DatabaseTaskSynchronizer synchronizer;
OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
@@ -354,229 +216,48 @@ void Database::markAsDeletedAndClose()
synchronizer.waitForTaskCompletion();
}
-class ContextRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
-public:
- static PassOwnPtr<ContextRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
- {
- return new ContextRemoveOpenDatabaseTask(database);
- }
-
- virtual void performTask(ScriptExecutionContext* context)
- {
- context->removeOpenDatabase(m_database.get());
- DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
- }
-
- virtual bool isCleanupTask() const { return true; }
-
-private:
- ContextRemoveOpenDatabaseTask(PassRefPtr<Database> database)
- : m_database(database)
- {
- }
-
- RefPtr<Database> m_database;
-};
-
void Database::close()
{
- RefPtr<Database> protect = this;
-
- if (!m_opened)
- return;
-
ASSERT(m_scriptExecutionContext->databaseThread());
ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
- m_sqliteDatabase.close();
- // Must ref() before calling databaseThread()->recordDatabaseClosed().
- m_scriptExecutionContext->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);
- }
- }
-
- m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
- m_scriptExecutionContext->postTask(ContextRemoveOpenDatabaseTask::create(this));
-}
-
-void Database::stop()
-{
- // FIXME: The net effect of the following code is to remove all pending transactions and statements, but allow the current statement
- // to run to completion. In the future we can use the sqlite3_progress_handler or sqlite3_interrupt interfaces to cancel the current
- // statement in response to close(), as well.
-
- // This method is meant to be used as an analog to cancelling a loader, and is used when a document is shut down as the result of
- // a page load or closing the page
- m_stopped = true;
{
MutexLocker locker(m_transactionInProgressMutex);
m_isTransactionQueueEnabled = false;
m_transactionInProgress = false;
}
-}
-
-unsigned long long Database::maximumSize() const
-{
- return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
-}
-
-void Database::disableAuthorizer()
-{
- ASSERT(m_databaseAuthorizer);
- m_databaseAuthorizer->disable();
-}
-
-void Database::enableAuthorizer()
-{
- ASSERT(m_databaseAuthorizer);
- m_databaseAuthorizer->enable();
-}
-
-void Database::setAuthorizerReadOnly()
-{
- ASSERT(m_databaseAuthorizer);
- m_databaseAuthorizer->setReadOnly();
-}
-static int guidForOriginAndName(const String& origin, const String& name)
-{
- String stringID;
- if (origin.endsWith("/"))
- stringID = origin + name;
- else
- stringID = origin + "/" + name;
-
- // Note: We don't have to use AtomicallyInitializedStatic here because
- // this function is called once in the constructor on the main thread
- // before any other threads that call this function are used.
- DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ());
- MutexLocker locker(stringIdentifierMutex);
- typedef HashMap<String, int> IDGuidMap;
- DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
- int guid = stringIdentifierToGUIDMap.get(stringID);
- if (!guid) {
- static int currentNewGUID = 1;
- guid = currentNewGUID++;
- stringIdentifierToGUIDMap.set(stringID, guid);
- }
+ closeDatabase();
- return guid;
+ // Must ref() before calling databaseThread()->recordDatabaseClosed().
+ RefPtr<Database> protect = this;
+ m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this);
+ m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
+ DatabaseTracker::tracker().removeOpenDatabase(this);
}
-void Database::resetAuthorizer()
+void Database::closeImmediately()
{
- if (m_databaseAuthorizer)
- m_databaseAuthorizer->reset();
+ DatabaseThread* databaseThread = scriptExecutionContext()->databaseThread();
+ if (databaseThread && !databaseThread->terminationRequested() && opened())
+ databaseThread->scheduleImmediateTask(DatabaseCloseTask::create(this, 0));
}
-void Database::performPolicyChecks()
+unsigned long long Database::maximumSize() const
{
- // FIXME: Code similar to the following will need to be run to enforce the per-origin size limit the spec mandates.
- // Additionally, we might need a way to pause the database thread while the UA prompts the user for permission to
- // increase the size limit
-
- /*
- if (m_databaseAuthorizer->lastActionIncreasedSize())
- DatabaseTracker::scheduleFileSizeCheckOnMainThread(this);
- */
-
- notImplemented();
+ return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
}
-bool Database::performOpenAndVerify(ExceptionCode& e)
+bool Database::performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode& e)
{
- if (!m_sqliteDatabase.open(m_filename)) {
- LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data());
- e = INVALID_STATE_ERR;
- return false;
- }
-
- ASSERT(m_databaseAuthorizer);
- m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
- m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
-
- String currentVersion;
- {
- MutexLocker locker(guidMutex());
-
- GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
- if (entry != guidToVersionMap().end()) {
- // 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 {
- LOG(StorageAPI, "No cached version for guid %i", m_guid);
-
- if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
- if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
- LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
- e = INVALID_STATE_ERR;
- // Close the handle to the database file.
- m_sqliteDatabase.close();
- return false;
- }
- }
-
- if (!getVersionFromDatabase(currentVersion)) {
- LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
- e = INVALID_STATE_ERR;
- // Close the handle to the database file.
- m_sqliteDatabase.close();
- return false;
- }
- if (currentVersion.length()) {
- LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
- } else {
- LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
- if (!setVersionInDatabase(m_expectedVersion)) {
- LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
- e = INVALID_STATE_ERR;
- // Close the handle to the database file.
- m_sqliteDatabase.close();
- return false;
- }
- currentVersion = m_expectedVersion;
- }
-
- updateGuidVersionMap(m_guid, currentVersion);
- }
- }
+ if (AbstractDatabase::performOpenAndVerify(setVersionInNewDatabase, e)) {
+ if (m_scriptExecutionContext->databaseThread())
+ m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
- if (currentVersion.isNull()) {
- LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
- currentVersion = "";
- }
-
- // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
- // If the expected version is the empty string, then we always return with whatever version of the database we have.
- if (m_expectedVersion.length() && m_expectedVersion != currentVersion) {
- LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
- databaseDebugName().ascii().data(), currentVersion.ascii().data());
- e = INVALID_STATE_ERR;
- // Close the handle to the database file.
- m_sqliteDatabase.close();
- return false;
+ return true;
}
- // All checks passed and we still have a handle to this database file.
- // Make sure DatabaseThread closes it when DatabaseThread goes away.
- m_opened = true;
- if (m_scriptExecutionContext->databaseThread())
- m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
-
- return true;
+ return false;
}
void Database::changeVersion(const String& oldVersion, const String& newVersion,
@@ -598,14 +279,20 @@ void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefP
scheduleTransaction();
}
+void Database::inProgressTransactionCompleted()
+{
+ MutexLocker locker(m_transactionInProgressMutex);
+ m_transactionInProgress = false;
+ scheduleTransaction();
+}
+
void Database::scheduleTransaction()
{
ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
RefPtr<SQLTransaction> transaction;
if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) {
- transaction = m_transactionQueue.first();
- m_transactionQueue.removeFirst();
+ transaction = m_transactionQueue.takeFirst();
}
if (transaction && m_scriptExecutionContext->databaseThread()) {
@@ -660,7 +347,7 @@ Vector<String> Database::performGetTableNames()
{
disableAuthorizer();
- SQLiteStatement statement(m_sqliteDatabase, "SELECT name FROM sqlite_master WHERE type='table';");
+ SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
enableAuthorizer();
@@ -695,14 +382,6 @@ SQLTransactionCoordinator* Database::transactionCoordinator() const
return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
}
-String Database::version() const
-{
- if (m_deleted)
- return String();
- MutexLocker locker(guidMutex());
- return guidToVersionMap().get(m_guid).threadsafeCopy();
-}
-
Vector<String> Database::tableNames()
{
// FIXME: Not using threadsafeCopy on these strings looks ok since threads take strict turns
@@ -720,46 +399,15 @@ Vector<String> Database::tableNames()
return result;
}
-void Database::setExpectedVersion(const String& version)
-{
- m_expectedVersion = version.threadsafeCopy();
- // Update the in memory database version map.
- MutexLocker locker(guidMutex());
- updateGuidVersionMap(m_guid, version);
-}
-
SecurityOrigin* Database::securityOrigin() const
{
- if (scriptExecutionContext()->isContextThread())
- return m_mainThreadSecurityOrigin.get();
+ if (m_scriptExecutionContext->isContextThread())
+ return m_contextThreadSecurityOrigin.get();
if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID())
return m_databaseThreadSecurityOrigin.get();
return 0;
}
-String Database::stringIdentifier() const
-{
- // Return a deep copy for ref counting thread safety
- return m_name.threadsafeCopy();
-}
-
-String Database::displayName() const
-{
- // Return a deep copy for ref counting thread safety
- return m_displayName.threadsafeCopy();
-}
-
-unsigned long Database::estimatedSize() const
-{
- return m_estimatedSize;
-}
-
-String Database::fileName() const
-{
- // Return a deep copy for ref counting thread safety
- return m_filename.threadsafeCopy();
-}
+} // namespace WebCore
#endif // ENABLE(DATABASE)
-
-} // namespace WebCore
diff --git a/WebCore/storage/Database.h b/WebCore/storage/Database.h
index 0d7f33c..e8482a7 100644
--- a/WebCore/storage/Database.h
+++ b/WebCore/storage/Database.h
@@ -30,154 +30,89 @@
#define Database_h
#if ENABLE(DATABASE)
+#include "AbstractDatabase.h"
+#include "ExceptionCode.h"
#include "PlatformString.h"
-#include "SecurityOrigin.h"
-#include "SQLiteDatabase.h"
-#include "SQLTransaction.h"
-#include "StringHash.h"
-#include "Timer.h"
-#include "VoidCallback.h"
-#include <wtf/Forward.h>
-#include <wtf/HashSet.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
#include <wtf/Deque.h>
-#else
-#include "PlatformString.h"
-#endif
+#include <wtf/Forward.h>
-#if ENABLE(DATABASE)
namespace WebCore {
-class DatabaseAuthorizer;
-class DatabaseThread;
+class DatabaseCallback;
class ScriptExecutionContext;
-class SQLResultSet;
+class SecurityOrigin;
+class SQLTransaction;
class SQLTransactionCallback;
class SQLTransactionClient;
class SQLTransactionCoordinator;
class SQLTransactionErrorCallback;
-class SQLValue;
+class VoidCallback;
-typedef int ExceptionCode;
-
-class Database : public ThreadSafeShared<Database> {
- friend class DatabaseTransactionTask;
- friend class SQLStatement;
- friend class SQLTransaction;
+class Database : public AbstractDatabase {
public:
- static void setIsAvailable(bool);
- static bool isAvailable();
-
- ~Database();
-
-// Direct support for the DOM API
- static PassRefPtr<Database> openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
- String version() const;
- void changeVersion(const String& oldVersion, const String& newVersion,
- PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
- PassRefPtr<VoidCallback> successCallback);
- void transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ virtual ~Database();
+
+ // Direct support for the DOM API
+ static PassRefPtr<Database> openDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
+ virtual String version() const;
+ void changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionCallback>,
+ PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback> successCallback);
+ void transaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
PassRefPtr<VoidCallback> successCallback, bool readOnly);
-// Internal engine support
- static const String& databaseInfoTableName();
-
- void disableAuthorizer();
- void enableAuthorizer();
- void setAuthorizerReadOnly();
-
+ // Internal engine support
Vector<String> tableNames();
- ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); }
- SecurityOrigin* securityOrigin() const;
- String stringIdentifier() const;
- String displayName() const;
- unsigned long estimatedSize() const;
- String fileName() const;
-
- bool getVersionFromDatabase(String&);
- bool setVersionInDatabase(const String&);
- void setExpectedVersion(const String&);
- bool versionMatchesExpected() const;
+ virtual SecurityOrigin* securityOrigin() const;
- void markAsDeletedAndClose();
+ virtual void markAsDeletedAndClose();
bool deleted() const { return m_deleted; }
void close();
- bool opened() const { return m_opened; }
-
- void stop();
- bool stopped() const { return m_stopped; }
+ virtual void closeImmediately();
unsigned long long databaseSize() const;
unsigned long long maximumSize() const;
-// Called from DatabaseThread, must be prepared to work on the background thread
- void resetAuthorizer();
- void performPolicyChecks();
-
- bool performOpenAndVerify(ExceptionCode&);
-
- Vector<String> performGetTableNames();
+ void scheduleTransactionCallback(SQLTransaction*);
+ void scheduleTransactionStep(SQLTransaction*, bool immediately = false);
SQLTransactionClient* transactionClient() const;
SQLTransactionCoordinator* transactionCoordinator() const;
private:
- Database(ScriptExecutionContext* context, const String& name,
- const String& expectedVersion, const String& displayName,
- unsigned long estimatedSize);
+ class DatabaseOpenTask;
+ class DatabaseCloseTask;
+ class DatabaseTransactionTask;
+ class DatabaseTableNamesTask;
+
+ Database(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize);
- bool openAndVerifyVersion(ExceptionCode&);
+ bool openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode&);
+ virtual bool performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode&);
+ void inProgressTransactionCompleted();
void scheduleTransaction();
- void scheduleTransactionCallback(SQLTransaction*);
- void scheduleTransactionStep(SQLTransaction* transaction, bool immediately = false);
+
+ Vector<String> performGetTableNames();
+
+ static void deliverPendingCallback(void*);
Deque<RefPtr<SQLTransaction> > m_transactionQueue;
Mutex m_transactionInProgressMutex;
bool m_transactionInProgress;
bool m_isTransactionQueueEnabled;
- static void deliverPendingCallback(void*);
-
- RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
- RefPtr<SecurityOrigin> m_mainThreadSecurityOrigin;
RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
- String m_name;
- int m_guid;
- String m_expectedVersion;
- String m_displayName;
- unsigned long m_estimatedSize;
- String m_filename;
bool m_deleted;
-
- bool m_stopped;
-
- bool m_opened;
-
- SQLiteDatabase m_sqliteDatabase;
- RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
-
-#ifndef NDEBUG
- String databaseDebugName() const { return m_mainThreadSecurityOrigin->toString() + "::" + m_name; }
-#endif
};
} // namespace WebCore
-#else
-
-namespace WebCore {
-class Database : public ThreadSafeShared<Database> {
-public:
- static const String& databaseInfoTableName();
-};
-} // namespace WebCore
-
#endif // ENABLE(DATABASE)
#endif // Database_h
diff --git a/WebCore/storage/Database.idl b/WebCore/storage/Database.idl
index c8a537c..ab79c97 100644
--- a/WebCore/storage/Database.idl
+++ b/WebCore/storage/Database.idl
@@ -30,7 +30,8 @@ module storage {
interface [
Conditional=DATABASE,
- OmitConstructor
+ OmitConstructor,
+ NoStaticTables
] Database {
readonly attribute DOMString version;
[Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
diff --git a/WebCore/storage/DatabaseAuthorizer.cpp b/WebCore/storage/DatabaseAuthorizer.cpp
index d87d4d9..79e47d4 100644
--- a/WebCore/storage/DatabaseAuthorizer.cpp
+++ b/WebCore/storage/DatabaseAuthorizer.cpp
@@ -29,13 +29,19 @@
#include "config.h"
#include "DatabaseAuthorizer.h"
-#include "Database.h"
#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
namespace WebCore {
-DatabaseAuthorizer::DatabaseAuthorizer()
+PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName)
+{
+ return adoptRef(new DatabaseAuthorizer(databaseInfoTableName));
+}
+
+DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName)
: m_securityEnabled(false)
+ , m_databaseInfoTableName(databaseInfoTableName)
{
reset();
addWhitelistedFunctions();
@@ -48,6 +54,11 @@ void DatabaseAuthorizer::reset()
m_readOnly = false;
}
+void DatabaseAuthorizer::resetDeletes()
+{
+ m_hadDeletes = false;
+}
+
void DatabaseAuthorizer::addWhitelistedFunctions()
{
// SQLite functions used to help implement some operations
@@ -102,6 +113,7 @@ void DatabaseAuthorizer::addWhitelistedFunctions()
m_whitelistedFunctions.add("total");
// SQLite FTS functions
+ m_whitelistedFunctions.add("match");
m_whitelistedFunctions.add("snippet");
m_whitelistedFunctions.add("offsets");
m_whitelistedFunctions.add("optimize");
@@ -136,7 +148,7 @@ int DatabaseAuthorizer::dropTable(const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::dropTempTable(const String& tableName)
@@ -147,7 +159,7 @@ int DatabaseAuthorizer::dropTempTable(const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::allowAlterTable(const String&, const String& tableName)
@@ -184,7 +196,7 @@ int DatabaseAuthorizer::dropIndex(const String&, const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
@@ -195,7 +207,7 @@ int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::createTrigger(const String&, const String& tableName)
@@ -223,7 +235,7 @@ int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
@@ -234,7 +246,7 @@ int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::createView(const String&)
@@ -252,7 +264,11 @@ int DatabaseAuthorizer::createTempView(const String&)
int DatabaseAuthorizer::dropView(const String&)
{
- return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
+ m_hadDeletes = true;
+ return SQLAuthAllow;
}
int DatabaseAuthorizer::dropTempView(const String&)
@@ -260,24 +276,36 @@ int DatabaseAuthorizer::dropTempView(const String&)
// SQLITE_DROP_TEMP_VIEW results in a DELETE operation, which is not
// allowed in read-only transactions or private browsing, so we might as
// well disallow SQLITE_DROP_TEMP_VIEW in these cases
- return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
+ m_hadDeletes = true;
+ return SQLAuthAllow;
}
-int DatabaseAuthorizer::createVTable(const String&, const String&)
+int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName)
{
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
+ // Allow only the FTS3 extension
+ if (!equalIgnoringCase(moduleName, "fts3"))
+ return SQLAuthDeny;
+
m_lastActionChangedDatabase = true;
- return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+ return denyBasedOnTableName(tableName);
}
-int DatabaseAuthorizer::dropVTable(const String&, const String&)
+int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName)
{
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+ // Allow only the FTS3 extension
+ if (!equalIgnoringCase(moduleName, "fts3"))
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::allowDelete(const String& tableName)
@@ -285,7 +313,7 @@ int DatabaseAuthorizer::allowDelete(const String& tableName)
if (m_readOnly && m_securityEnabled)
return SQLAuthDeny;
- return denyBasedOnTableName(tableName);
+ return updateDeletesBasedOnTableName(tableName);
}
int DatabaseAuthorizer::allowInsert(const String& tableName)
@@ -365,7 +393,7 @@ void DatabaseAuthorizer::setReadOnly()
m_readOnly = true;
}
-int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName)
+int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const
{
if (!m_securityEnabled)
return SQLAuthAllow;
@@ -376,10 +404,18 @@ int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName)
// equalIgnoringCase(tableName, "sqlite_sequence") || equalIgnoringCase(tableName, Database::databaseInfoTableName()))
// return SQLAuthDeny;
- if (equalIgnoringCase(tableName, Database::databaseInfoTableName()))
+ if (equalIgnoringCase(tableName, m_databaseInfoTableName))
return SQLAuthDeny;
return SQLAuthAllow;
}
+int DatabaseAuthorizer::updateDeletesBasedOnTableName(const String& tableName)
+{
+ int allow = denyBasedOnTableName(tableName);
+ if (allow)
+ m_hadDeletes = true;
+ return allow;
+}
+
} // namespace WebCore
diff --git a/WebCore/storage/DatabaseAuthorizer.h b/WebCore/storage/DatabaseAuthorizer.h
index 037409e..af6e016 100644
--- a/WebCore/storage/DatabaseAuthorizer.h
+++ b/WebCore/storage/DatabaseAuthorizer.h
@@ -28,10 +28,11 @@
#ifndef DatabaseAuthorizer_h
#define DatabaseAuthorizer_h
+#include "PlatformString.h"
#include "StringHash.h"
+#include <wtf/Forward.h>
#include <wtf/HashSet.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
@@ -43,7 +44,7 @@ extern const int SQLAuthDeny;
class DatabaseAuthorizer : public ThreadSafeShared<DatabaseAuthorizer> {
public:
- static PassRefPtr<DatabaseAuthorizer> create() { return adoptRef(new DatabaseAuthorizer); }
+ static PassRefPtr<DatabaseAuthorizer> create(const String& databaseInfoTableName);
int createTable(const String& tableName);
int createTempTable(const String& tableName);
@@ -90,19 +91,25 @@ public:
void setReadOnly();
void reset();
+ void resetDeletes();
bool lastActionWasInsert() const { return m_lastActionWasInsert; }
bool lastActionChangedDatabase() const { return m_lastActionChangedDatabase; }
+ bool hadDeletes() const { return m_hadDeletes; }
private:
- DatabaseAuthorizer();
+ DatabaseAuthorizer(const String& databaseInfoTableName);
void addWhitelistedFunctions();
- int denyBasedOnTableName(const String&);
+ int denyBasedOnTableName(const String&) const;
+ int updateDeletesBasedOnTableName(const String&);
bool m_securityEnabled : 1;
bool m_lastActionWasInsert : 1;
bool m_lastActionChangedDatabase : 1;
bool m_readOnly : 1;
+ bool m_hadDeletes : 1;
+
+ const String m_databaseInfoTableName;
HashSet<String, CaseFoldingHash> m_whitelistedFunctions;
};
diff --git a/WebCore/storage/DatabaseCallback.h b/WebCore/storage/DatabaseCallback.h
new file mode 100644
index 0000000..9ece2a3
--- /dev/null
+++ b/WebCore/storage/DatabaseCallback.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DatabaseCallback_h
+#define DatabaseCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class Database;
+class DatabaseSync;
+class ScriptExecutionContext;
+
+class DatabaseCallback : public ThreadSafeShared<DatabaseCallback> {
+public:
+ virtual ~DatabaseCallback() { }
+ virtual bool handleEvent(ScriptExecutionContext*, Database*) = 0;
+ virtual bool handleEvent(ScriptExecutionContext*, DatabaseSync*) = 0;
+};
+
+}
+
+#endif
+
+#endif // DatabaseCallback_h
diff --git a/WebCore/storage/DatabaseCallback.idl b/WebCore/storage/DatabaseCallback.idl
new file mode 100644
index 0000000..c218680
--- /dev/null
+++ b/WebCore/storage/DatabaseCallback.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] DatabaseCallback {
+ boolean handleEvent(in Database database);
+ boolean handleEvent(in DatabaseSync database);
+ };
+}
diff --git a/WebCore/storage/DatabaseDetails.h b/WebCore/storage/DatabaseDetails.h
index 9b0f506..ceebd35 100644
--- a/WebCore/storage/DatabaseDetails.h
+++ b/WebCore/storage/DatabaseDetails.h
@@ -41,6 +41,9 @@ public:
: m_expectedUsage(0)
, m_currentUsage(0)
{
+#ifndef NDEBUG
+ m_thread = currentThread();
+#endif
}
DatabaseDetails(const String& databaseName, const String& displayName, unsigned long long expectedUsage, unsigned long long currentUsage)
@@ -49,19 +52,27 @@ public:
, m_expectedUsage(expectedUsage)
, m_currentUsage(currentUsage)
{
+#ifndef NDEBUG
+ m_thread = currentThread();
+#endif
}
const String& name() const { return m_name; }
const String& displayName() const { return m_displayName; }
unsigned long long expectedUsage() const { return m_expectedUsage; }
unsigned long long currentUsage() const { return m_currentUsage; }
+#ifndef NDEBUG
+ ThreadIdentifier thread() const { return m_thread; }
+#endif
private:
String m_name;
String m_displayName;
unsigned long long m_expectedUsage;
unsigned long long m_currentUsage;
-
+#ifndef NDEBUG
+ ThreadIdentifier m_thread;
+#endif
};
} // namespace WebCore
diff --git a/WebCore/storage/DatabaseSync.cpp b/WebCore/storage/DatabaseSync.cpp
new file mode 100644
index 0000000..f64c27f
--- /dev/null
+++ b/WebCore/storage/DatabaseSync.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DatabaseSync.h"
+
+#if ENABLE(DATABASE)
+#include "DatabaseCallback.h"
+#include "DatabaseTracker.h"
+#include "Logging.h"
+#include "SQLException.h"
+#include "SQLTransactionSync.h"
+#include "SQLTransactionSyncCallback.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<DatabaseSync> DatabaseSync::openDatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec)
+{
+ ASSERT(context->isContextThread());
+
+ if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
+ LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
+ return 0;
+ }
+
+ RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(context, name, expectedVersion, displayName, estimatedSize));
+
+ if (!database->performOpenAndVerify(!creationCallback, ec)) {
+ LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
+ DatabaseTracker::tracker().removeOpenDatabase(database.get());
+ return 0;
+ }
+
+ DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+
+ if (database->isNew() && creationCallback.get()) {
+ database->m_expectedVersion = "";
+ LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get());
+ creationCallback->handleEvent(context, database.get());
+ }
+
+ return database;
+}
+
+DatabaseSync::DatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize)
+ : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize)
+{
+}
+
+DatabaseSync::~DatabaseSync()
+{
+ ASSERT(m_scriptExecutionContext->isContextThread());
+
+ if (opened()) {
+ DatabaseTracker::tracker().removeOpenDatabase(this);
+ closeDatabase();
+ }
+}
+
+void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionCode& ec)
+{
+ ASSERT(m_scriptExecutionContext->isContextThread());
+
+ if (sqliteDatabase().transactionInProgress()) {
+ ec = SQLException::DATABASE_ERR;
+ return;
+ }
+
+ RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false);
+ if ((ec = transaction->begin()))
+ return;
+
+ String actualVersion;
+ if (!getVersionFromDatabase(actualVersion)) {
+ ec = SQLException::UNKNOWN_ERR;
+ return;
+ }
+
+ if (actualVersion != oldVersion) {
+ ec = SQLException::VERSION_ERR;
+ return;
+ }
+
+ if ((ec = transaction->execute()))
+ return;
+
+ if (!setVersionInDatabase(newVersion)) {
+ ec = SQLException::UNKNOWN_ERR;
+ return;
+ }
+
+ if ((ec = transaction->commit()))
+ return;
+
+ setExpectedVersion(newVersion);
+}
+
+void DatabaseSync::transaction(PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionCode& ec)
+{
+ ASSERT(m_scriptExecutionContext->isContextThread());
+
+ if (sqliteDatabase().transactionInProgress()) {
+ ec = SQLException::DATABASE_ERR;
+ return;
+ }
+
+ RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly);
+ if ((ec = transaction->begin()) || (ec = transaction->execute()) || (ec = transaction->commit()))
+ transaction->rollback();
+}
+
+void DatabaseSync::markAsDeletedAndClose()
+{
+ // FIXME: need to do something similar to closeImmediately(), but in a sync way
+}
+
+class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<CloseSyncDatabaseOnContextThreadTask> create(PassRefPtr<DatabaseSync> database)
+ {
+ return new CloseSyncDatabaseOnContextThreadTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_database->closeImmediately();
+ }
+
+private:
+ CloseSyncDatabaseOnContextThreadTask(PassRefPtr<DatabaseSync> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<DatabaseSync> m_database;
+};
+
+void DatabaseSync::closeImmediately()
+{
+ if (!m_scriptExecutionContext->isContextThread()) {
+ m_scriptExecutionContext->postTask(CloseSyncDatabaseOnContextThreadTask::create(this));
+ return;
+ }
+
+ if (!opened())
+ return;
+
+ DatabaseTracker::tracker().removeOpenDatabase(this);
+
+ closeDatabase();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/DatabaseSync.h b/WebCore/storage/DatabaseSync.h
new file mode 100644
index 0000000..2019f85
--- /dev/null
+++ b/WebCore/storage/DatabaseSync.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DatabaseSync_h
+#define DatabaseSync_h
+
+#if ENABLE(DATABASE)
+#include "AbstractDatabase.h"
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#ifndef NDEBUG
+#include "SecurityOrigin.h"
+#endif
+
+namespace WebCore {
+
+class DatabaseCallback;
+class SQLTransactionSync;
+class SQLTransactionSyncCallback;
+class ScriptExecutionContext;
+class SecurityOrigin;
+
+// Instances of this class should be created and used only on the worker's context thread.
+class DatabaseSync : public AbstractDatabase {
+public:
+ virtual ~DatabaseSync();
+
+ static PassRefPtr<DatabaseSync> openDatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
+ void changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback>, ExceptionCode&);
+ void transaction(PassRefPtr<SQLTransactionSyncCallback>, bool readOnly, ExceptionCode&);
+
+ virtual void markAsDeletedAndClose();
+ virtual void closeImmediately();
+
+private:
+ DatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // DatabaseSync_h
diff --git a/WebCore/storage/DatabaseSync.idl b/WebCore/storage/DatabaseSync.idl
new file mode 100644
index 0000000..30adf38
--- /dev/null
+++ b/WebCore/storage/DatabaseSync.idl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=DATABASE,
+ OmitConstructor,
+ NoStaticTables
+ ] DatabaseSync {
+ readonly attribute DOMString version;
+ [Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionSyncCallback callback);
+ [Custom] void transaction(in SQLTransactionSyncCallback callback);
+ [Custom] void readTransaction(in SQLTransactionSyncCallback callback);
+ };
+
+}
diff --git a/WebCore/storage/DatabaseTask.cpp b/WebCore/storage/DatabaseTask.cpp
index 702c96b..3526d9d 100644
--- a/WebCore/storage/DatabaseTask.cpp
+++ b/WebCore/storage/DatabaseTask.cpp
@@ -78,7 +78,6 @@ void DatabaseTask::performTask()
m_database->resetAuthorizer();
doPerformTask();
- m_database->performPolicyChecks();
if (m_synchronizer)
m_synchronizer->taskCompleted();
@@ -87,21 +86,22 @@ void DatabaseTask::performTask()
// *** DatabaseOpenTask ***
// Opens the database file and verifies the version matches the expected version.
-DatabaseOpenTask::DatabaseOpenTask(Database* database, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
+Database::DatabaseOpenTask::DatabaseOpenTask(Database* database, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
: DatabaseTask(database, synchronizer)
+ , m_setVersionInNewDatabase(setVersionInNewDatabase)
, m_code(code)
, m_success(success)
{
ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
}
-void DatabaseOpenTask::doPerformTask()
+void Database::DatabaseOpenTask::doPerformTask()
{
- m_success = database()->performOpenAndVerify(m_code);
+ m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_code);
}
#ifndef NDEBUG
-const char* DatabaseOpenTask::debugTaskName() const
+const char* Database::DatabaseOpenTask::debugTaskName() const
{
return "DatabaseOpenTask";
}
@@ -110,18 +110,18 @@ const char* DatabaseOpenTask::debugTaskName() const
// *** DatabaseCloseTask ***
// Closes the database.
-DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
+Database::DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
: DatabaseTask(database, synchronizer)
{
}
-void DatabaseCloseTask::doPerformTask()
+void Database::DatabaseCloseTask::doPerformTask()
{
database()->close();
}
#ifndef NDEBUG
-const char* DatabaseCloseTask::debugTaskName() const
+const char* Database::DatabaseCloseTask::debugTaskName() const
{
return "DatabaseCloseTask";
}
@@ -130,27 +130,20 @@ const char* DatabaseCloseTask::debugTaskName() const
// *** DatabaseTransactionTask ***
// Starts a transaction that will report its results via a callback.
-DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction)
+Database::DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction)
: DatabaseTask(transaction->database(), 0)
, m_transaction(transaction)
{
}
-DatabaseTransactionTask::~DatabaseTransactionTask()
+void Database::DatabaseTransactionTask::doPerformTask()
{
-}
-
-void DatabaseTransactionTask::doPerformTask()
-{
- if (m_transaction->performNextStep()) {
- // The transaction is complete, we can move on to the next one.
- MutexLocker locker(m_transaction->database()->m_transactionInProgressMutex);
- m_transaction->database()->scheduleTransaction();
- }
+ if (m_transaction->performNextStep())
+ m_transaction->database()->inProgressTransactionCompleted();
}
#ifndef NDEBUG
-const char* DatabaseTransactionTask::debugTaskName() const
+const char* Database::DatabaseTransactionTask::debugTaskName() const
{
return "DatabaseTransactionTask";
}
@@ -159,20 +152,20 @@ const char* DatabaseTransactionTask::debugTaskName() const
// *** DatabaseTableNamesTask ***
// Retrieves a list of all tables in the database - for WebInspector support.
-DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
+Database::DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
: DatabaseTask(database, synchronizer)
, m_tableNames(names)
{
ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
}
-void DatabaseTableNamesTask::doPerformTask()
+void Database::DatabaseTableNamesTask::doPerformTask()
{
m_tableNames = database()->performGetTableNames();
}
#ifndef NDEBUG
-const char* DatabaseTableNamesTask::debugTaskName() const
+const char* Database::DatabaseTableNamesTask::debugTaskName() const
{
return "DatabaseTableNamesTask";
}
diff --git a/WebCore/storage/DatabaseTask.h b/WebCore/storage/DatabaseTask.h
index 998e373..9673a26 100644
--- a/WebCore/storage/DatabaseTask.h
+++ b/WebCore/storage/DatabaseTask.h
@@ -29,8 +29,10 @@
#define DatabaseTask_h
#if ENABLE(DATABASE)
+#include "Database.h"
#include "ExceptionCode.h"
#include "PlatformString.h"
+#include "SQLTransaction.h"
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
@@ -39,14 +41,6 @@
namespace WebCore {
-class Database;
-class DatabaseTask;
-class DatabaseThread;
-class SQLValue;
-class SQLCallback;
-class SQLTransaction;
-class VersionChangeCallback;
-
// Can be used to wait until DatabaseTask is completed.
// Has to be passed into DatabaseTask::create to be associated with the task.
class DatabaseTaskSynchronizer : public Noncopyable {
@@ -66,7 +60,6 @@ private:
};
class DatabaseTask : public Noncopyable {
- friend class Database;
public:
virtual ~DatabaseTask();
@@ -89,29 +82,30 @@ private:
#endif
};
-class DatabaseOpenTask : public DatabaseTask {
+class Database::DatabaseOpenTask : public DatabaseTask {
public:
- static PassOwnPtr<DatabaseOpenTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
+ static PassOwnPtr<DatabaseOpenTask> create(Database* db, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
{
- return new DatabaseOpenTask(db, synchronizer, code, success);
+ return new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success);
}
private:
- DatabaseOpenTask(Database*, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success);
+ DatabaseOpenTask(Database*, bool setVersionInNewDatabase, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success);
virtual void doPerformTask();
#ifndef NDEBUG
virtual const char* debugTaskName() const;
#endif
+ bool m_setVersionInNewDatabase;
ExceptionCode& m_code;
bool& m_success;
};
-class DatabaseCloseTask : public DatabaseTask {
+class Database::DatabaseCloseTask : public DatabaseTask {
public:
static PassOwnPtr<DatabaseCloseTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer)
- {
+ {
return new DatabaseCloseTask(db, synchronizer);
}
@@ -124,7 +118,7 @@ private:
#endif
};
-class DatabaseTransactionTask : public DatabaseTask {
+class Database::DatabaseTransactionTask : public DatabaseTask {
public:
// Transaction task is never synchronous, so no 'synchronizer' parameter.
static PassOwnPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction)
@@ -134,7 +128,6 @@ public:
SQLTransaction* transaction() const { return m_transaction.get(); }
- virtual ~DatabaseTransactionTask();
private:
DatabaseTransactionTask(PassRefPtr<SQLTransaction>);
@@ -146,7 +139,7 @@ private:
RefPtr<SQLTransaction> m_transaction;
};
-class DatabaseTableNamesTask : public DatabaseTask {
+class Database::DatabaseTableNamesTask : public DatabaseTask {
public:
static PassOwnPtr<DatabaseTableNamesTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
{
diff --git a/WebCore/storage/DatabaseThread.cpp b/WebCore/storage/DatabaseThread.cpp
index ec4c6d1..ae2a6c0 100644
--- a/WebCore/storage/DatabaseThread.cpp
+++ b/WebCore/storage/DatabaseThread.cpp
@@ -113,14 +113,14 @@ void* DatabaseThread::databaseThread()
openSetCopy.swap(m_openDatabaseSet);
DatabaseSet::iterator end = openSetCopy.end();
for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it)
- (*it)->close();
+ (*it)->close();
}
// Detach the thread so its resources are no longer of any concern to anyone else
detachThread(m_threadID);
DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;
-
+
// Clear the self refptr, possibly resulting in deletion
m_selfRef = 0;
diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp
index 76492c9..de38ec3 100644
--- a/WebCore/storage/DatabaseTracker.cpp
+++ b/WebCore/storage/DatabaseTracker.cpp
@@ -31,9 +31,9 @@
#if ENABLE(DATABASE)
+#include "AbstractDatabase.h"
#include "Chrome.h"
#include "ChromeClient.h"
-#include "Database.h"
#include "DatabaseThread.h"
#include "DatabaseTrackerClient.h"
#include "Logging.h"
@@ -49,53 +49,64 @@
using namespace std;
+static WebCore::OriginQuotaManager& originQuotaManager()
+{
+ DEFINE_STATIC_LOCAL(WebCore::OriginQuotaManager, quotaManager, ());
+ return quotaManager;
+}
+
namespace WebCore {
-OriginQuotaManager& DatabaseTracker::originQuotaManager()
+static DatabaseTracker* staticTracker = 0;
+
+void DatabaseTracker::initializeTracker(const String& databasePath)
{
- populateOrigins();
- ASSERT(m_quotaManager);
- return *m_quotaManager;
+ ASSERT(!staticTracker);
+ if (staticTracker)
+ return;
+
+ staticTracker = new DatabaseTracker(databasePath);
}
DatabaseTracker& DatabaseTracker::tracker()
{
- DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ());
- return tracker;
+ if (!staticTracker)
+ staticTracker = new DatabaseTracker("");
+
+ return *staticTracker;
}
-DatabaseTracker::DatabaseTracker()
+DatabaseTracker::DatabaseTracker(const String& databasePath)
: m_client(0)
- , m_proposedDatabase(0)
-#ifndef NDEBUG
- , m_thread(currentThread())
-#endif
{
+ setDatabaseDirectoryPath(databasePath);
+
SQLiteFileSystem::registerSQLiteVFS();
+
+ MutexLocker lockDatabase(m_databaseGuard);
+ populateOrigins();
}
void DatabaseTracker::setDatabaseDirectoryPath(const String& path)
{
- ASSERT(currentThread() == m_thread);
+ MutexLocker lockDatabase(m_databaseGuard);
ASSERT(!m_database.isOpen());
- m_databaseDirectoryPath = path;
+ m_databaseDirectoryPath = path.threadsafeCopy();
}
-const String& DatabaseTracker::databaseDirectoryPath() const
+String DatabaseTracker::databaseDirectoryPath() const
{
- ASSERT(currentThread() == m_thread);
- return m_databaseDirectoryPath;
+ return m_databaseDirectoryPath.threadsafeCopy();
}
String DatabaseTracker::trackerDatabasePath() const
{
- ASSERT(currentThread() == m_thread);
return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, "Databases.db");
}
void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
if (m_database.isOpen())
return;
@@ -106,67 +117,94 @@ void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
if (!m_database.open(databasePath)) {
// FIXME: What do do here?
+ LOG_ERROR("Failed to open databasePath %s.", databasePath.ascii().data());
return;
}
+ m_database.disableThreadingChecks();
if (!m_database.tableExists("Origins")) {
if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) {
// FIXME: and here
+ LOG_ERROR("Failed to create Origins table");
}
}
if (!m_database.tableExists("Databases")) {
if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) {
// FIXME: and here
+ LOG_ERROR("Failed to create Databases table");
}
}
}
bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize)
{
- ASSERT(currentThread() == m_thread);
+ SecurityOrigin* origin = context->securityOrigin();
+ ProposedDatabase details;
- // Populate the origins before we establish a database; this guarantees that quotaForOrigin
- // can run on the database thread later.
- populateOrigins();
+ unsigned long long requirement;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- SecurityOrigin* origin = context->securityOrigin();
+ if (!canCreateDatabase(origin, name))
+ return false;
- // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker
- // by fetching it's current usage now
- unsigned long long usage = usageForOrigin(origin);
+ recordCreatingDatabase(origin, name);
- // If a database already exists, ignore the passed-in estimated size and say it's OK.
- if (hasEntryForDatabase(origin, name))
- return true;
+ // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker
+ // by fetching its current usage now.
+ unsigned long long usage = usageForOriginNoLock(origin);
- // If the database will fit, allow its creation.
- unsigned long long requirement = usage + max(1UL, estimatedSize);
- if (requirement < usage)
- return false; // If the estimated size is so big it causes an overflow, don't allow creation.
- if (requirement <= quotaForOrigin(origin))
- return true;
+ // If a database already exists, ignore the passed-in estimated size and say it's OK.
+ if (hasEntryForDatabase(origin, name))
+ return true;
- // Give the chrome client a chance to increase the quota.
- // Temporarily make the details of the proposed database available, so the client can get at them.
- pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0));
- m_proposedDatabase = &details;
+ // If the database will fit, allow its creation.
+ requirement = usage + max(1UL, estimatedSize);
+ if (requirement < usage) {
+ doneCreatingDatabase(origin, name);
+ return false; // If the estimated size is so big it causes an overflow, don't allow creation.
+ }
+ if (requirement <= quotaForOriginNoLock(origin))
+ return true;
+
+ // Give the chrome client a chance to increase the quota.
+ // Temporarily make the details of the proposed database available, so the client can get at them.
+ // FIXME: We should really just pass the details into this call, rather than using m_proposedDatabases.
+ details = ProposedDatabase(origin->threadsafeCopy(), DatabaseDetails(name.threadsafeCopy(), displayName.threadsafeCopy(), estimatedSize, 0));
+ m_proposedDatabases.add(&details);
+ }
+ // Drop all locks before calling out; we don't know what they'll do.
context->databaseExceededQuota(name);
- m_proposedDatabase = 0;
+
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ m_proposedDatabases.remove(&details);
// If the database will fit now, allow its creation.
- return requirement <= quotaForOrigin(origin);
+ if (requirement <= quotaForOriginNoLock(origin))
+ return true;
+
+ doneCreatingDatabase(origin, name);
+
+ return false;
}
-bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin)
+bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
return m_quotaMap->contains(origin);
}
+bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ return hasEntryForOriginNoLock(origin);
+}
+
bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
openTrackerDatabase(false);
if (!m_database.isOpen())
return false;
@@ -181,28 +219,35 @@ bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
return statement.step() == SQLResultRow;
}
-unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
+unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
{
- ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
// The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
// plus the current usage of the given database
- Locker<OriginQuotaManager> locker(originQuotaManager());
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
SecurityOrigin* origin = database->securityOrigin();
- return quotaForOrigin(origin) - originQuotaManager().diskUsage(origin) + SQLiteFileSystem::getDatabaseFileSize(database->fileName());
+ return quotaForOriginNoLock(origin) - originQuotaManager().diskUsage(origin) + SQLiteFileSystem::getDatabaseFileSize(database->fileName());
+}
+
+void DatabaseTracker::databaseChanged(AbstractDatabase* database)
+{
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().markDatabase(database);
}
String DatabaseTracker::originPath(SecurityOrigin* origin) const
{
- ASSERT(currentThread() == m_thread);
- return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, origin->databaseIdentifier());
+ return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.threadsafeCopy(), origin->databaseIdentifier());
}
-String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
+String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const String& name, bool createIfNotExists)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(!originQuotaManager().tryLock());
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return String();
+ for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter)
+ if ((*iter)->second.name() == name && (*iter)->first->equal(origin))
+ return String();
String originIdentifier = origin->databaseIdentifier();
String originPath = this->originPath(origin);
@@ -212,7 +257,6 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return String();
// See if we have a path for this database yet
- openTrackerDatabase(false);
if (!m_database.isOpen())
return String();
SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
@@ -231,36 +275,39 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return String();
if (result != SQLResultDone) {
- LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data());
+ LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.ascii().data(), name.ascii().data());
return String();
}
statement.finalize();
- String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, origin->databaseIdentifier(), &m_database);
+ String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, originIdentifier, &m_database);
if (!addDatabase(origin, name, fileName))
return String();
// If this origin's quota is being tracked (open handle to a database in this origin), add this new database
// to the quota manager now
String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, fileName);
- {
- Locker<OriginQuotaManager> locker(originQuotaManager());
- if (originQuotaManager().tracksOrigin(origin))
- originQuotaManager().addDatabase(origin, name, fullFilePath);
- }
+ if (originQuotaManager().tracksOrigin(origin))
+ originQuotaManager().addDatabase(origin, name, fullFilePath);
return fullFilePath;
}
+String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+
+ return fullPathForDatabaseNoLock(origin, name, createIfNotExists).threadsafeCopy();
+}
+
void DatabaseTracker::populateOrigins()
{
+ ASSERT(!m_databaseGuard.tryLock());
if (m_quotaMap)
return;
- ASSERT(currentThread() == m_thread);
-
m_quotaMap.set(new QuotaMap);
- m_quotaManager.set(new OriginQuotaManager);
openTrackerDatabase(false);
if (!m_database.isOpen())
@@ -268,30 +315,31 @@ void DatabaseTracker::populateOrigins()
SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare statement.");
return;
+ }
int result;
while ((result = statement.step()) == SQLResultRow) {
RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0));
- m_quotaMap->set(origin.get(), statement.getColumnInt64(1));
+ m_quotaMap->set(origin.get()->threadsafeCopy(), statement.getColumnInt64(1));
}
if (result != SQLResultDone)
- LOG_ERROR("Failed to read in all origins from the database");
+ LOG_ERROR("Failed to read in all origins from the database.");
}
void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result)
{
- ASSERT(currentThread() == m_thread);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(m_quotaMap);
copyKeysToVector(*m_quotaMap, result);
}
-bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
+bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
openTrackerDatabase(false);
if (!m_database.isOpen())
return false;
@@ -315,44 +363,67 @@ bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri
return true;
}
-DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
+bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
{
- ASSERT(currentThread() == m_thread);
+ Vector<String> temp;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ if (!databaseNamesForOriginNoLock(origin, temp))
+ return false;
+ }
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return m_proposedDatabase->second;
+ for (Vector<String>::iterator iter = temp.begin(); iter != temp.end(); ++iter)
+ resultVector.append(iter->threadsafeCopy());
+ return true;
+}
+DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
+{
String originIdentifier = origin->databaseIdentifier();
+ String displayName;
+ int64_t expectedUsage;
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return DatabaseDetails();
- SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
- if (statement.prepare() != SQLResultOk)
- return DatabaseDetails();
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
- statement.bindText(1, originIdentifier);
- statement.bindText(2, name);
+ for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter)
+ if ((*iter)->second.name() == name && (*iter)->first->equal(origin)) {
+ ASSERT((*iter)->second.thread() == currentThread());
+ return (*iter)->second;
+ }
- int result = statement.step();
- if (result == SQLResultDone)
- return DatabaseDetails();
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return DatabaseDetails();
+ SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
+ if (statement.prepare() != SQLResultOk)
+ return DatabaseDetails();
+
+ statement.bindText(1, originIdentifier);
+ statement.bindText(2, name);
+
+ int result = statement.step();
+ if (result == SQLResultDone)
+ return DatabaseDetails();
- if (result != SQLResultRow) {
- LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
- return DatabaseDetails();
+ if (result != SQLResultRow) {
+ LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
+ return DatabaseDetails();
+ }
+ displayName = statement.getColumnText(0);
+ expectedUsage = statement.getColumnInt64(1);
}
- return DatabaseDetails(name, statement.getColumnText(0), statement.getColumnInt64(1), usageForDatabase(name, origin));
+ return DatabaseDetails(name, displayName, expectedUsage, usageForDatabase(name, origin));
}
void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
{
- ASSERT(currentThread() == m_thread);
-
String originIdentifier = origin->databaseIdentifier();
int64_t guid = 0;
+ MutexLocker lockDatabase(m_databaseGuard);
+
openTrackerDatabase(true);
if (!m_database.isOpen())
return;
@@ -400,7 +471,6 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
unsigned long long DatabaseTracker::usageForDatabase(const String& name, SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
String path = fullPathForDatabase(origin, name, false);
if (path.isEmpty())
return 0;
@@ -408,77 +478,93 @@ unsigned long long DatabaseTracker::usageForDatabase(const String& name, Securit
return SQLiteFileSystem::getDatabaseFileSize(path);
}
-void DatabaseTracker::addOpenDatabase(Database* database)
+void DatabaseTracker::addOpenDatabase(AbstractDatabase* database)
{
if (!database)
return;
- MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
- if (!m_openDatabaseMap)
- m_openDatabaseMap.set(new DatabaseOriginMap);
+ if (!m_openDatabaseMap)
+ m_openDatabaseMap.set(new DatabaseOriginMap);
- String name(database->stringIdentifier());
- DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
- if (!nameMap) {
- nameMap = new DatabaseNameMap;
- m_openDatabaseMap->set(database->securityOrigin(), nameMap);
- }
+ String name(database->stringIdentifier());
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
+ if (!nameMap) {
+ nameMap = new DatabaseNameMap;
+ m_openDatabaseMap->set(database->securityOrigin()->threadsafeCopy(), nameMap);
+ }
- DatabaseSet* databaseSet = nameMap->get(name);
- if (!databaseSet) {
- databaseSet = new DatabaseSet;
- nameMap->set(name, databaseSet);
- }
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet) {
+ databaseSet = new DatabaseSet;
+ nameMap->set(name.threadsafeCopy(), databaseSet);
+ }
+
+ databaseSet->add(database);
- databaseSet->add(database);
+ LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
- LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ if (!originQuotaManager().tracksOrigin(database->securityOrigin())) {
+ originQuotaManager().trackOrigin(database->securityOrigin());
+ originQuotaManager().addDatabase(database->securityOrigin(), database->stringIdentifier(), database->fileName());
+ }
+ }
+
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneCreatingDatabase(database->securityOrigin(), database->stringIdentifier());
}
-void DatabaseTracker::removeOpenDatabase(Database* database)
+void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database)
{
if (!database)
return;
- MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
- if (!m_openDatabaseMap) {
- ASSERT_NOT_REACHED();
- return;
- }
+ if (!m_openDatabaseMap) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
- String name(database->stringIdentifier());
- DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
- if (!nameMap) {
- ASSERT_NOT_REACHED();
- return;
- }
+ String name(database->stringIdentifier());
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
+ if (!nameMap) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
- DatabaseSet* databaseSet = nameMap->get(name);
- if (!databaseSet) {
- ASSERT_NOT_REACHED();
- return;
- }
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
- databaseSet->remove(database);
+ databaseSet->remove(database);
- LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
+ LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
- if (!databaseSet->isEmpty())
- return;
+ if (!databaseSet->isEmpty())
+ return;
- nameMap->remove(name);
- delete databaseSet;
+ nameMap->remove(name);
+ delete databaseSet;
- if (!nameMap->isEmpty())
- return;
+ if (!nameMap->isEmpty())
+ return;
+
+ m_openDatabaseMap->remove(database->securityOrigin());
+ delete nameMap;
- m_openDatabaseMap->remove(database->securityOrigin());
- delete nameMap;
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().removeOrigin(database->securityOrigin());
+ }
}
-void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases)
+void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases)
{
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
if (!m_openDatabaseMap)
@@ -496,10 +582,9 @@ void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam
databases->add(*it);
}
-unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
+unsigned long long DatabaseTracker::usageForOriginNoLock(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
- Locker<OriginQuotaManager> locker(originQuotaManager());
+ ASSERT(!originQuotaManager().tryLock());
// Use the OriginQuotaManager mechanism to calculate the usage
if (originQuotaManager().tracksOrigin(origin))
@@ -509,79 +594,89 @@ unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
originQuotaManager().trackOrigin(origin);
Vector<String> names;
- databaseNamesForOrigin(origin, names);
+ databaseNamesForOriginNoLock(origin, names);
for (unsigned i = 0; i < names.size(); ++i)
- originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(origin, names[i], false));
+ originQuotaManager().addDatabase(origin, names[i], fullPathForDatabaseNoLock(origin, names[i], false));
if (!originQuotaManager().tracksOrigin(origin))
return 0;
return originQuotaManager().diskUsage(origin);
}
-unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin)
+unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread || m_quotaMap);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ return usageForOriginNoLock(origin);
+}
+
+unsigned long long DatabaseTracker::quotaForOriginNoLock(SecurityOrigin* origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
return m_quotaMap->get(origin);
}
+unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ return quotaForOriginNoLock(origin);
+}
+
void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
{
- ASSERT(currentThread() == m_thread);
- if (quotaForOrigin(origin) == quota)
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ if (quotaForOriginNoLock(origin) == quota)
return;
openTrackerDatabase(true);
if (!m_database.isOpen())
return;
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
-
- if (!m_quotaMap->contains(origin)) {
- SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- } else {
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindInt64(2, quota);
-
- if (statement.step() != SQLResultDone)
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- }
+ if (!m_quotaMap->contains(origin)) {
+ SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
} else {
- SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
- bool error = statement.prepare() != SQLResultOk;
- if (!error) {
- statement.bindInt64(1, quota);
- statement.bindText(2, origin->databaseIdentifier());
-
- error = !statement.executeCommand();
- }
+ statement.bindText(1, origin->databaseIdentifier());
+ statement.bindInt64(2, quota);
- if (error)
- LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
+ if (statement.step() != SQLResultDone)
+ LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
+ }
+ } else {
+ SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
+ bool error = statement.prepare() != SQLResultOk;
+ if (!error) {
+ statement.bindInt64(1, quota);
+ statement.bindText(2, origin->databaseIdentifier());
+
+ error = !statement.executeCommand();
}
- // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
- m_quotaMap->set(origin, quota);
+ if (error)
+ LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
}
+ // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
+ m_quotaMap->set(origin->threadsafeCopy(), quota);
+
if (m_client)
m_client->dispatchDidModifyOrigin(origin);
}
bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, const String& path)
{
- ASSERT(currentThread() == m_thread);
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(m_quotaMap);
openTrackerDatabase(true);
if (!m_database.isOpen())
return false;
// New database should never be added until the origin has been established
- ASSERT(hasEntryForOrigin(origin));
+ ASSERT(hasEntryForOriginNoLock(origin));
SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
@@ -605,8 +700,6 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
void DatabaseTracker::deleteAllDatabases()
{
- ASSERT(currentThread() == m_thread);
-
Vector<RefPtr<SecurityOrigin> > originsCopy;
origins(originsCopy);
@@ -614,19 +707,30 @@ void DatabaseTracker::deleteAllDatabases()
deleteOrigin(originsCopy[i].get());
}
-void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
+// It is the caller's responsibility to make sure that nobody is trying to create, delete, open, or close databases in this origin while the deletion is
+// taking place.
+bool DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
-
Vector<String> databaseNames;
- if (!databaseNamesForOrigin(origin, databaseNames)) {
- LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
- return;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return false;
+
+ if (!databaseNamesForOriginNoLock(origin, databaseNames)) {
+ LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
+ if (!canDeleteOrigin(origin)) {
+ LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin->databaseIdentifier().ascii().data());
+ ASSERT(false);
+ return false;
+ }
+ recordDeletingOrigin(origin);
}
+ // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
for (unsigned i = 0; i < databaseNames.size(); ++i) {
if (!deleteDatabaseFile(origin, databaseNames[i])) {
// Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
@@ -634,41 +738,45 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
}
}
- SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneDeletingOrigin(origin);
- statement.bindText(1, origin->databaseIdentifier());
+ SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
+ if (statement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
- if (!statement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ statement.bindText(1, origin->databaseIdentifier());
- SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
- if (originStatement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ if (!statement.executeCommand()) {
+ LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
- originStatement.bindText(1, origin->databaseIdentifier());
+ SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
+ if (originStatement.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
- if (!originStatement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
+ originStatement.bindText(1, origin->databaseIdentifier());
+
+ if (!originStatement.executeCommand()) {
+ LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
- SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
+ SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
- RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
+ RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
m_quotaMap->remove(origin);
- Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- originQuotaManager().removeOrigin(origin);
+ {
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().removeOrigin(origin);
+ }
// If we removed the last origin, do some additional deletion.
if (m_quotaMap->isEmpty()) {
@@ -677,31 +785,159 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath());
SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath);
}
+
+ if (m_client) {
+ m_client->dispatchDidModifyOrigin(origin);
+ for (unsigned i = 0; i < databaseNames.size(); ++i)
+ m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
+ }
}
+ return true;
+}
- if (m_client) {
- m_client->dispatchDidModifyOrigin(origin);
- for (unsigned i = 0; i < databaseNames.size(); ++i)
- m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
+bool DatabaseTracker::canCreateDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ // Can't create a database while someone else is deleting it; there's a risk of leaving untracked database debris on the disk.
+ return !deletingDatabase(origin, name) && !deletingOrigin(origin);
+}
+
+void DatabaseTracker::recordCreatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ if (!nameMap) {
+ nameMap = new NameCountMap();
+ m_beingCreated.set(origin->threadsafeCopy(), nameMap);
}
+ long count = nameMap->get(name);
+ nameMap->set(name.threadsafeCopy(), count + 1);
}
-void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
+void DatabaseTracker::doneCreatingDatabase(SecurityOrigin *origin, const String& name)
{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ if (nameMap) {
+ long count = nameMap->get(name);
+ ASSERT(count > 0);
+ if (count <= 1) {
+ nameMap->remove(name);
+ if (nameMap->isEmpty()) {
+ m_beingCreated.remove(origin);
+ delete nameMap;
+ }
+ } else
+ nameMap->set(name, count - 1);
+ } else
+ ASSERT(false);
+}
+
+bool DatabaseTracker::creatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameCountMap* nameMap = m_beingCreated.get(origin);
+ return nameMap && nameMap->get(name);
+}
+
+bool DatabaseTracker::canDeleteDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return !creatingDatabase(origin, name) && !deletingDatabase(origin, name);
+}
+
+void DatabaseTracker::recordDeletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(canDeleteDatabase(origin, name));
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ if (!nameSet) {
+ nameSet = new NameSet();
+ m_beingDeleted.set(origin->threadsafeCopy(), nameSet);
+ }
+ ASSERT(!nameSet->contains(name));
+ nameSet->add(name.threadsafeCopy());
+}
+
+void DatabaseTracker::doneDeletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ if (nameSet) {
+ ASSERT(nameSet->contains(name));
+ nameSet->remove(name);
+ if (nameSet->isEmpty()) {
+ m_beingDeleted.remove(origin);
+ delete nameSet;
+ }
+ } else {
+ ASSERT(false);
+ }
+}
+bool DatabaseTracker::deletingDatabase(SecurityOrigin *origin, const String& name)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ NameSet* nameSet = m_beingDeleted.get(origin);
+ return nameSet && nameSet->contains(name);
+}
+
+bool DatabaseTracker::canDeleteOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return !(deletingOrigin(origin) || m_beingCreated.get(origin));
+}
+
+bool DatabaseTracker::deletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ return m_originsBeingDeleted.contains(origin);
+}
+
+void DatabaseTracker::recordDeletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(!deletingOrigin(origin));
+ m_originsBeingDeleted.add(origin->threadsafeCopy());
+}
+
+void DatabaseTracker::doneDeletingOrigin(SecurityOrigin *origin)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(deletingOrigin(origin));
+ m_originsBeingDeleted.remove(origin);
+}
+
+bool DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
+{
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return false;
+
+ if (!canDeleteDatabase(origin, name)) {
+ ASSERT(FALSE);
+ return false;
+ }
+ recordDeletingDatabase(origin, name);
+ }
+
+ // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
if (!deleteDatabaseFile(origin, name)) {
LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneDeletingDatabase(origin, name);
+ return false;
}
+ MutexLocker lockDatabase(m_databaseGuard);
+
SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
+ doneDeletingDatabase(origin, name);
+ return false;
}
statement.bindText(1, origin->databaseIdentifier());
@@ -709,7 +945,8 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
if (!statement.executeCommand()) {
LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
+ doneDeletingDatabase(origin, name);
+ return false;
}
{
@@ -721,28 +958,38 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
m_client->dispatchDidModifyOrigin(origin);
m_client->dispatchDidModifyDatabase(origin, name);
}
+ doneDeletingDatabase(origin, name);
+
+ return true;
}
+// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them. While this is in progress, the caller
+// is responsible for making sure no new databases are opened in the file to be deleted.
bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name)
{
- ASSERT(currentThread() == m_thread);
String fullPath = fullPathForDatabase(origin, name, false);
if (fullPath.isEmpty())
return true;
- Vector<RefPtr<Database> > deletedDatabases;
+#ifndef NDEBUG
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(deletingDatabase(origin, name) || deletingOrigin(origin));
+ }
+#endif
+
+ Vector<RefPtr<AbstractDatabase> > deletedDatabases;
- // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
+ // Make sure not to hold the any locks when calling
// Database::markAsDeletedAndClose(), since that can cause a deadlock
// during the synchronous DatabaseThread call it triggers.
-
{
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
if (m_openDatabaseMap) {
// There are some open databases, lets check if they are for this origin.
DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
if (nameMap && nameMap->size()) {
- // There are some open databases for this origin, lets check
+ // There are some open databases for this origin, let's check
// if they are this database by name.
DatabaseSet* databaseSet = nameMap->get(name);
if (databaseSet && databaseSet->size()) {
@@ -763,7 +1010,6 @@ bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& n
void DatabaseTracker::setClient(DatabaseTrackerClient* client)
{
- ASSERT(currentThread() == m_thread);
m_client = client;
}
@@ -773,7 +1019,7 @@ static Mutex& notificationMutex()
return mutex;
}
-typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue;
+typedef Vector<pair<RefPtr<SecurityOrigin>, String> > NotificationQueue;
static NotificationQueue& notificationQueue()
{
@@ -785,7 +1031,7 @@ void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, cons
{
MutexLocker locker(notificationMutex());
- notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.crossThreadString()));
+ notificationQueue().append(pair<RefPtr<SecurityOrigin>, String>(origin->threadsafeCopy(), name.crossThreadString()));
scheduleForNotification();
}
@@ -820,7 +1066,7 @@ void DatabaseTracker::notifyDatabasesChanged(void*)
return;
for (unsigned i = 0; i < notifications.size(); ++i)
- theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, notifications[i].second);
+ theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first.get(), notifications[i].second);
}
diff --git a/WebCore/storage/DatabaseTracker.h b/WebCore/storage/DatabaseTracker.h
index 4640b18..094ee66 100644
--- a/WebCore/storage/DatabaseTracker.h
+++ b/WebCore/storage/DatabaseTracker.h
@@ -44,7 +44,7 @@
namespace WebCore {
-class Database;
+class AbstractDatabase;
class ScriptExecutionContext;
class SecurityOrigin;
@@ -52,32 +52,36 @@ struct SecurityOriginHash;
#if !PLATFORM(CHROMIUM)
class DatabaseTrackerClient;
-class OriginQuotaManager;
struct SecurityOriginTraits;
#endif // !PLATFORM(CHROMIUM)
class DatabaseTracker : public Noncopyable {
public:
+ static void initializeTracker(const String& databasePath);
static DatabaseTracker& tracker();
- // FIXME: Due to workers having multiple threads in a single process sharing
- // a DatabaseTracker, this singleton will have to be synchronized or moved
- // to TLS.
+ // This singleton will potentially be used from multiple worker threads and the page's context thread simultaneously. To keep this safe, it's
+ // currently using 4 locks. In order to avoid deadlock when taking multiple locks, you must take them in the correct order:
+ // m_databaseGuard before quotaManager if both locks are needed.
+ // m_openDatabaseMapGuard before quotaManager if both locks are needed.
+ // m_databaseGuard and m_openDatabaseMapGuard currently don't overlap.
+ // notificationMutex() is currently independent of the other locks.
bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize);
void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize);
String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true);
- void addOpenDatabase(Database*);
- void removeOpenDatabase(Database*);
- void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases);
+ void addOpenDatabase(AbstractDatabase*);
+ void removeOpenDatabase(AbstractDatabase*);
+ void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases);
- unsigned long long getMaxSizeForDatabase(const Database*);
+ unsigned long long getMaxSizeForDatabase(const AbstractDatabase*);
+ void databaseChanged(AbstractDatabase*);
private:
- DatabaseTracker();
+ DatabaseTracker(const String& databasePath);
- typedef HashSet<Database*> DatabaseSet;
+ typedef HashSet<AbstractDatabase*> DatabaseSet;
typedef HashMap<String, DatabaseSet*> DatabaseNameMap;
typedef HashMap<RefPtr<SecurityOrigin>, DatabaseNameMap*, SecurityOriginHash> DatabaseOriginMap;
@@ -87,7 +91,7 @@ private:
#if !PLATFORM(CHROMIUM)
public:
void setDatabaseDirectoryPath(const String&);
- const String& databaseDirectoryPath() const;
+ String databaseDirectoryPath() const;
void origins(Vector<RefPtr<SecurityOrigin> >& result);
bool databaseNamesForOrigin(SecurityOrigin*, Vector<String>& result);
@@ -100,20 +104,23 @@ public:
void setQuota(SecurityOrigin*, unsigned long long);
void deleteAllDatabases();
- void deleteOrigin(SecurityOrigin*);
- void deleteDatabase(SecurityOrigin*, const String& name);
+ bool deleteOrigin(SecurityOrigin*);
+ bool deleteDatabase(SecurityOrigin*, const String& name);
void setClient(DatabaseTrackerClient*);
// From a secondary thread, must be thread safe with its data
void scheduleNotifyDatabaseChanged(SecurityOrigin*, const String& name);
- OriginQuotaManager& originQuotaManager();
-
-
bool hasEntryForOrigin(SecurityOrigin*);
private:
+ bool hasEntryForOriginNoLock(SecurityOrigin* origin);
+ String fullPathForDatabaseNoLock(SecurityOrigin*, const String& name, bool createIfDoesNotExist);
+ bool databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector);
+ unsigned long long usageForOriginNoLock(SecurityOrigin* origin);
+ unsigned long long quotaForOriginNoLock(SecurityOrigin* origin);
+
String trackerDatabasePath() const;
void openTrackerDatabase(bool createIfDoesNotExist);
@@ -126,23 +133,38 @@ private:
bool deleteDatabaseFile(SecurityOrigin*, const String& name);
+ // This lock protects m_database, m_quotaMap, m_proposedDatabases, m_databaseDirectoryPath, m_originsBeingDeleted, m_beingCreated, and m_beingDeleted.
+ Mutex m_databaseGuard;
SQLiteDatabase m_database;
typedef HashMap<RefPtr<SecurityOrigin>, unsigned long long, SecurityOriginHash> QuotaMap;
- Mutex m_quotaMapGuard;
mutable OwnPtr<QuotaMap> m_quotaMap;
- OwnPtr<OriginQuotaManager> m_quotaManager;
-
String m_databaseDirectoryPath;
DatabaseTrackerClient* m_client;
- std::pair<SecurityOrigin*, DatabaseDetails>* m_proposedDatabase;
-
-#ifndef NDEBUG
- ThreadIdentifier m_thread;
-#endif
+ typedef std::pair<RefPtr<SecurityOrigin>, DatabaseDetails> ProposedDatabase;
+ HashSet<ProposedDatabase*> m_proposedDatabases;
+
+ typedef HashMap<String, long> NameCountMap;
+ typedef HashMap<RefPtr<SecurityOrigin>, NameCountMap*, SecurityOriginHash> CreateSet;
+ CreateSet m_beingCreated;
+ typedef HashSet<String> NameSet;
+ HashMap<RefPtr<SecurityOrigin>, NameSet*, SecurityOriginHash> m_beingDeleted;
+ HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash> m_originsBeingDeleted;
+ bool canCreateDatabase(SecurityOrigin *origin, const String& name);
+ void recordCreatingDatabase(SecurityOrigin *origin, const String& name);
+ void doneCreatingDatabase(SecurityOrigin *origin, const String& name);
+ bool creatingDatabase(SecurityOrigin *origin, const String& name);
+ bool canDeleteDatabase(SecurityOrigin *origin, const String& name);
+ void recordDeletingDatabase(SecurityOrigin *origin, const String& name);
+ void doneDeletingDatabase(SecurityOrigin *origin, const String& name);
+ bool deletingDatabase(SecurityOrigin *origin, const String& name);
+ bool canDeleteOrigin(SecurityOrigin *origin);
+ bool deletingOrigin(SecurityOrigin *origin);
+ void recordDeletingOrigin(SecurityOrigin *origin);
+ void doneDeletingOrigin(SecurityOrigin *origin);
static void scheduleForNotification();
static void notifyDatabasesChanged(void*);
diff --git a/WebCore/storage/IDBAny.cpp b/WebCore/storage/IDBAny.cpp
new file mode 100644
index 0000000..9a18980
--- /dev/null
+++ b/WebCore/storage/IDBAny.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBAny.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBDatabaseRequest.h"
+#include "IDBIndexRequest.h"
+#include "IDBObjectStoreRequest.h"
+#include "IndexedDatabaseRequest.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBAny> IDBAny::create()
+{
+ return adoptRef(new IDBAny());
+}
+
+IDBAny::IDBAny()
+ : m_type(UndefinedType)
+{
+}
+
+IDBAny::~IDBAny()
+{
+}
+
+PassRefPtr<IDBDatabaseRequest> IDBAny::idbDatabaseRequest()
+{
+ ASSERT(m_type == IDBDatabaseRequestType);
+ return m_idbDatabaseRequest;
+}
+
+PassRefPtr<IDBIndexRequest> IDBAny::idbIndexRequest()
+{
+ ASSERT(m_type == IDBIndexRequestType);
+ return m_idbIndexRequest;
+}
+
+PassRefPtr<IDBKey> IDBAny::idbKey()
+{
+ ASSERT(m_type == IDBKeyType);
+ return m_idbKey;
+}
+
+PassRefPtr<IDBObjectStoreRequest> IDBAny::idbObjectStoreRequest()
+{
+ ASSERT(m_type == IDBObjectStoreRequestType);
+ return m_idbObjectStoreRequest;
+}
+
+PassRefPtr<IndexedDatabaseRequest> IDBAny::indexedDatabaseRequest()
+{
+ ASSERT(m_type == IndexedDatabaseRequestType);
+ return m_indexedDatabaseRequest;
+}
+
+PassRefPtr<SerializedScriptValue> IDBAny::serializedScriptValue()
+{
+ ASSERT(m_type == SerializedScriptValueType);
+ return m_serializedScriptValue;
+}
+
+void IDBAny::set()
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = NullType;
+}
+
+void IDBAny::set(PassRefPtr<IDBDatabaseRequest> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBDatabaseRequestType;
+ m_idbDatabaseRequest = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBIndexRequest> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBDatabaseRequestType;
+ m_idbIndexRequest = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBKey> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBKeyType;
+ m_idbKey = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBObjectStoreRequest> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBObjectStoreRequestType;
+ m_idbObjectStoreRequest = value;
+}
+
+void IDBAny::set(PassRefPtr<IndexedDatabaseRequest> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IndexedDatabaseRequestType;
+ m_indexedDatabaseRequest = value;
+}
+
+void IDBAny::set(PassRefPtr<SerializedScriptValue> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = SerializedScriptValueType;
+ m_serializedScriptValue = value;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBAny.h b/WebCore/storage/IDBAny.h
new file mode 100644
index 0000000..77bba7c
--- /dev/null
+++ b/WebCore/storage/IDBAny.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBAny_h
+#define IDBAny_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBDatabaseRequest;
+class IDBIndexRequest;
+class IDBKey;
+class IDBObjectStoreRequest;
+class IndexedDatabaseRequest;
+class SerializedScriptValue;
+
+class IDBAny : public RefCounted<IDBAny> {
+public:
+ static PassRefPtr<IDBAny> create();
+ template<typename T>
+ static PassRefPtr<IDBAny> create(T* idbObject)
+ {
+ RefPtr<IDBAny> any = IDBAny::create();
+ any->set(idbObject);
+ return any.release();
+ }
+ ~IDBAny();
+
+ enum Type {
+ UndefinedType = 0,
+ NullType,
+ IDBDatabaseRequestType,
+ IDBIndexRequestType,
+ IDBKeyType,
+ IDBObjectStoreRequestType,
+ IndexedDatabaseRequestType,
+ SerializedScriptValueType
+ };
+
+ Type type() const { return m_type; }
+ // Use type() to figure out which one of these you're allowed to call.
+ PassRefPtr<IDBDatabaseRequest> idbDatabaseRequest();
+ PassRefPtr<IDBIndexRequest> idbIndexRequest();
+ PassRefPtr<IDBKey> idbKey();
+ PassRefPtr<IDBObjectStoreRequest> idbObjectStoreRequest();
+ PassRefPtr<IndexedDatabaseRequest> indexedDatabaseRequest();
+ PassRefPtr<SerializedScriptValue> serializedScriptValue();
+
+ // Set can only be called once.
+ void set(); // For "null".
+ void set(PassRefPtr<IDBDatabaseRequest>);
+ void set(PassRefPtr<IDBIndexRequest>);
+ void set(PassRefPtr<IDBKey>);
+ void set(PassRefPtr<IDBObjectStoreRequest>);
+ void set(PassRefPtr<IndexedDatabaseRequest>);
+ void set(PassRefPtr<SerializedScriptValue>);
+
+private:
+ IDBAny();
+
+ Type m_type;
+
+ // Only one of the following should ever be in use at any given time.
+ RefPtr<IDBDatabaseRequest> m_idbDatabaseRequest;
+ RefPtr<IDBIndexRequest> m_idbIndexRequest;
+ RefPtr<IDBKey> m_idbKey;
+ RefPtr<IDBObjectStoreRequest> m_idbObjectStoreRequest;
+ RefPtr<IndexedDatabaseRequest> m_indexedDatabaseRequest;
+ RefPtr<SerializedScriptValue> m_serializedScriptValue;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBAny_h
diff --git a/WebCore/storage/IDBAny.idl b/WebCore/storage/IDBAny.idl
new file mode 100644
index 0000000..19d8424
--- /dev/null
+++ b/WebCore/storage/IDBAny.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE,
+ CustomToJS
+ ] IDBAny {
+ // This space is intentionally left blank.
+ };
+}
diff --git a/WebCore/storage/IDBCallbacks.h b/WebCore/storage/IDBCallbacks.h
new file mode 100644
index 0000000..37fdc46
--- /dev/null
+++ b/WebCore/storage/IDBCallbacks.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBCallbacks_h
+#define IDBCallbacks_h
+
+#include "IDBDatabase.h"
+#include "IDBDatabaseError.h"
+#include "IDBIndex.h"
+#include "IDBKey.h"
+#include "IDBObjectStore.h"
+#include "SerializedScriptValue.h"
+#include <wtf/RefCounted.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBCallbacks : public RefCounted<IDBCallbacks> {
+public:
+ virtual ~IDBCallbacks() { }
+
+ virtual void onError(PassRefPtr<IDBDatabaseError>) = 0;
+ virtual void onSuccess() = 0; // For "null".
+ virtual void onSuccess(PassRefPtr<IDBDatabase>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBIndex>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBKey>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBObjectStore>) = 0;
+ virtual void onSuccess(PassRefPtr<SerializedScriptValue>) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBCallbacks_h
diff --git a/WebCore/storage/IDBDatabase.h b/WebCore/storage/IDBDatabase.h
new file mode 100644
index 0000000..0055ad1
--- /dev/null
+++ b/WebCore/storage/IDBDatabase.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBDatabase_h
+#define IDBDatabase_h
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+class Frame;
+class IDBCallbacks;
+class IDBObjectStore;
+
+// This class is shared by IDBDatabaseRequest (async) and IDBDatabaseSync (sync).
+// This is implemented by IDBDatabaseImpl and optionally others (in order to proxy
+// calls across process barriers). All calls to these classes should be non-blocking and
+// trigger work on a background thread if necessary.
+class IDBDatabase : public ThreadSafeShared<IDBDatabase> {
+public:
+ virtual ~IDBDatabase() { }
+
+ virtual String name() const = 0;
+ virtual String description() const = 0;
+ virtual String version() const = 0;
+ virtual PassRefPtr<DOMStringList> objectStores() const = 0;
+
+ // FIXME: Add transaction and setVersion.
+
+ virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>) = 0;
+ virtual PassRefPtr<IDBObjectStore> objectStore(const String& name, unsigned short mode) = 0;
+ virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabase_h
diff --git a/WebCore/storage/IDBDatabaseError.h b/WebCore/storage/IDBDatabaseError.h
index e8fd2dd..c345ff9 100644
--- a/WebCore/storage/IDBDatabaseError.h
+++ b/WebCore/storage/IDBDatabaseError.h
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -25,6 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#ifndef IDBDatabaseError_h
#define IDBDatabaseError_h
@@ -38,19 +36,20 @@ namespace WebCore {
class IDBDatabaseError : public RefCounted<IDBDatabaseError> {
public:
- static PassRefPtr<IDBDatabaseError> create()
+ static PassRefPtr<IDBDatabaseError> create(unsigned short code, const String& message)
{
- return adoptRef(new IDBDatabaseError());
+ return adoptRef(new IDBDatabaseError(code, message));
}
~IDBDatabaseError() { }
unsigned short code() const { return m_code; }
void setCode(unsigned short value) { m_code = value; }
- String message() const { return m_message; }
+ const String& message() const { return m_message; }
void setMessage(const String& value) { m_message = value; }
private:
- IDBDatabaseError() { }
+ IDBDatabaseError(unsigned short code, const String& message)
+ : m_code(code), m_message(message) { }
unsigned short m_code;
String m_message;
@@ -61,4 +60,3 @@ private:
#endif
#endif // IDBDatabaseError_h
-
diff --git a/WebCore/storage/IDBDatabaseError.idl b/WebCore/storage/IDBDatabaseError.idl
index 6c6019c..2912a1d 100644
--- a/WebCore/storage/IDBDatabaseError.idl
+++ b/WebCore/storage/IDBDatabaseError.idl
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -25,6 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
module storage {
interface [
diff --git a/WebCore/storage/IDBDatabaseException.h b/WebCore/storage/IDBDatabaseException.h
index d94a7f9..251cfc9 100644
--- a/WebCore/storage/IDBDatabaseException.h
+++ b/WebCore/storage/IDBDatabaseException.h
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -25,6 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#ifndef IDBDatabaseException_h
#define IDBDatabaseException_h
@@ -43,7 +41,22 @@ public:
return adoptRef(new IDBDatabaseException());
}
~IDBDatabaseException() { }
-
+
+ // Keep in sync with what's in the .idl file.
+ enum ErrorCode {
+ UNKNOWN_ERR = 0,
+ NON_TRANSIENT_ERR = 1,
+ NOT_FOUND_ERR = 2,
+ CONSTRAINT_ERR = 3,
+ DATA_ERR = 4,
+ NOT_ALLOWED_ERR = 5,
+ SERIAL_ERR = 11,
+ RECOVERABLE_ERR = 21,
+ TRANSIENT_ERR = 31,
+ TIMEOUT_ERR = 32,
+ DEADLOCK_ERR = 33
+ };
+
unsigned short code() const { return m_code; }
void setCode(unsigned short value) { m_code = value; }
String message() const { return m_message; }
@@ -61,4 +74,3 @@ private:
#endif
#endif // IDBDatabaseException_h
-
diff --git a/WebCore/storage/IDBDatabaseException.idl b/WebCore/storage/IDBDatabaseException.idl
index 898e5f9..88e6e7e 100644
--- a/WebCore/storage/IDBDatabaseException.idl
+++ b/WebCore/storage/IDBDatabaseException.idl
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -25,6 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
module storage {
interface [
@@ -41,6 +39,7 @@ module storage {
const unsigned short TRANSIENT_ERR = 31;
const unsigned short TIMEOUT_ERR = 32;
const unsigned short DEADLOCK_ERR = 33;
+
attribute unsigned short code;
attribute DOMString message;
};
diff --git a/WebCore/storage/IDBDatabaseImpl.cpp b/WebCore/storage/IDBDatabaseImpl.cpp
new file mode 100644
index 0000000..162efab
--- /dev/null
+++ b/WebCore/storage/IDBDatabaseImpl.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBDatabaseImpl.h"
+
+#include "DOMStringList.h"
+#include "IDBDatabaseException.h"
+#include "IDBObjectStoreImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBDatabaseImpl::IDBDatabaseImpl(const String& name, const String& description, const String& version)
+ : m_name(name)
+ , m_description(description)
+ , m_version(version)
+{
+}
+
+IDBDatabaseImpl::~IDBDatabaseImpl()
+{
+}
+
+PassRefPtr<DOMStringList> IDBDatabaseImpl::objectStores() const
+{
+ RefPtr<DOMStringList> objectStoreNames = DOMStringList::create();
+ for (ObjectStoreMap::const_iterator it = m_objectStores.begin(); it != m_objectStores.end(); ++it)
+ objectStoreNames->append(it->first);
+ return objectStoreNames.release();
+}
+
+void IDBDatabaseImpl::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks> callbacks)
+{
+ if (m_objectStores.contains(name)) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "An objectStore with that name already exists."));
+ return;
+ }
+
+ RefPtr<IDBObjectStore> objectStore = IDBObjectStoreImpl::create(name, keyPath, autoIncrement);
+ m_objectStores.set(name, objectStore);
+ callbacks->onSuccess(objectStore.release());
+}
+
+PassRefPtr<IDBObjectStore> IDBDatabaseImpl::objectStore(const String& name, unsigned short mode)
+{
+ // FIXME: If no transaction is running, this should implicitly start one.
+ ASSERT_UNUSED(mode, !mode); // FIXME: Handle non-standard modes.
+ return m_objectStores.get(name);
+}
+
+void IDBDatabaseImpl::removeObjectStore(const String& name, PassRefPtr<IDBCallbacks> callbacks)
+{
+ if (!m_objectStores.contains(name)) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "No objectStore with that name exists."));
+ return;
+ }
+
+ m_objectStores.remove(name);
+ callbacks->onSuccess();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBDatabaseImpl.h b/WebCore/storage/IDBDatabaseImpl.h
new file mode 100644
index 0000000..7203c5a
--- /dev/null
+++ b/WebCore/storage/IDBDatabaseImpl.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBDatabaseImpl_h
+#define IDBDatabaseImpl_h
+
+#include "IDBCallbacks.h"
+#include "IDBDatabase.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseImpl : public IDBDatabase {
+public:
+ static PassRefPtr<IDBDatabase> create(const String& name, const String& description, const String& version)
+ {
+ return adoptRef(new IDBDatabaseImpl(name, description, version));
+ }
+ virtual ~IDBDatabaseImpl();
+
+ // Implements IDBDatabase
+ virtual String name() const { return m_name; }
+ virtual String description() const { return m_description; }
+ virtual String version() const { return m_version; }
+ virtual PassRefPtr<DOMStringList> objectStores() const;
+
+ virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>);
+ virtual PassRefPtr<IDBObjectStore> objectStore(const String& name, unsigned short mode);
+ virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>);
+
+private:
+ IDBDatabaseImpl(const String& name, const String& description, const String& version);
+
+ String m_name;
+ String m_description;
+ String m_version;
+
+ typedef HashMap<String, RefPtr<IDBObjectStore> > ObjectStoreMap;
+ ObjectStoreMap m_objectStores;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseImpl_h
diff --git a/WebCore/storage/IDBDatabaseRequest.cpp b/WebCore/storage/IDBDatabaseRequest.cpp
new file mode 100644
index 0000000..fce2671
--- /dev/null
+++ b/WebCore/storage/IDBDatabaseRequest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBDatabaseRequest.h"
+
+#include "IDBAny.h"
+#include "IDBObjectStoreRequest.h"
+#include "IDBRequest.h"
+#include "IndexedDatabase.h"
+#include "ScriptExecutionContext.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBDatabaseRequest::IDBDatabaseRequest(PassRefPtr<IDBDatabase> database)
+ : m_database(database)
+{
+ // We pass a reference to this object before it can be adopted.
+ relaxAdoptionRequirement();
+}
+
+IDBDatabaseRequest::~IDBDatabaseRequest()
+{
+}
+
+PassRefPtr<IDBRequest> IDBDatabaseRequest::createObjectStore(ScriptExecutionContext* context, const String& name, const String& keyPath, bool autoIncrement)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_database->createObjectStore(name, keyPath, autoIncrement, request);
+ return request;
+}
+
+PassRefPtr<IDBObjectStoreRequest> IDBDatabaseRequest::objectStore(const String& name, unsigned short mode)
+{
+ RefPtr<IDBObjectStore> objectStore = m_database->objectStore(name, mode);
+ ASSERT(objectStore); // FIXME: If this is null, we should raise a NOT_FOUND_ERR.
+ return IDBObjectStoreRequest::create(objectStore.release());
+}
+
+PassRefPtr<IDBRequest> IDBDatabaseRequest::removeObjectStore(ScriptExecutionContext* context, const String& name)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_database->removeObjectStore(name, request);
+ return request;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBDatabaseRequest.h b/WebCore/storage/IDBDatabaseRequest.h
new file mode 100644
index 0000000..fd19882
--- /dev/null
+++ b/WebCore/storage/IDBDatabaseRequest.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBDatabaseRequest_h
+#define IDBDatabaseRequest_h
+
+#include "DOMStringList.h"
+#include "IDBDatabase.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBAny;
+class IDBObjectStoreRequest;
+class IDBRequest;
+class ScriptExecutionContext;
+
+class IDBDatabaseRequest : public RefCounted<IDBDatabaseRequest> {
+public:
+ static PassRefPtr<IDBDatabaseRequest> create(PassRefPtr<IDBDatabase> database)
+ {
+ return adoptRef(new IDBDatabaseRequest(database));
+ }
+ ~IDBDatabaseRequest();
+
+ // Implement the IDL
+ String name() const { return m_database->name(); }
+ String description() const { return m_database->description(); }
+ String version() const { return m_database->version(); }
+ PassRefPtr<DOMStringList> objectStores() const { return m_database->objectStores(); }
+
+ PassRefPtr<IDBRequest> createObjectStore(ScriptExecutionContext*, const String& name, const String& keyPath = String(), bool autoIncrement = false);
+ PassRefPtr<IDBObjectStoreRequest> objectStore(const String& name, unsigned short mode = 0); // FIXME: Use constant rather than 0.
+ PassRefPtr<IDBRequest> removeObjectStore(ScriptExecutionContext*, const String& name);
+
+private:
+ IDBDatabaseRequest(PassRefPtr<IDBDatabase>);
+
+ RefPtr<IDBDatabase> m_database;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseRequest_h
diff --git a/WebCore/storage/IDBDatabaseRequest.idl b/WebCore/storage/IDBDatabaseRequest.idl
new file mode 100644
index 0000000..548b221
--- /dev/null
+++ b/WebCore/storage/IDBDatabaseRequest.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBDatabaseRequest {
+ readonly attribute DOMString name;
+ readonly attribute DOMString description;
+ readonly attribute DOMString version;
+ readonly attribute DOMStringList objectStores;
+
+ // FIXME: Add transaction.
+ // FIXME: Add setVersion.
+
+ [CallWith=ScriptExecutionContext] IDBRequest createObjectStore(in DOMString name, in [Optional, ConvertNullToNullString] DOMString keyPath, in [Optional] boolean autoIncrement);
+ // FIXME: objectStore needs to be able to raise an IDBDatabaseException.
+ IDBObjectStoreRequest objectStore(in DOMString name, in [Optional] unsigned short mode);
+ [CallWith=ScriptExecutionContext] IDBRequest removeObjectStore(in DOMString name);
+ };
+
+}
diff --git a/WebCore/storage/IDBErrorEvent.cpp b/WebCore/storage/IDBErrorEvent.cpp
new file mode 100644
index 0000000..cba980d
--- /dev/null
+++ b/WebCore/storage/IDBErrorEvent.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBErrorEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+#include "IDBDatabaseError.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBErrorEvent> IDBErrorEvent::create(PassRefPtr<IDBAny> source, const IDBDatabaseError& error)
+{
+ return adoptRef(new IDBErrorEvent(source, error));
+}
+
+IDBErrorEvent::IDBErrorEvent(PassRefPtr<IDBAny> source, const IDBDatabaseError& error)
+ : IDBEvent(eventNames().errorEvent, source)
+ , m_code(error.code())
+ , m_message(error.message())
+{
+}
+
+IDBErrorEvent::~IDBErrorEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBErrorEvent.h b/WebCore/storage/IDBErrorEvent.h
new file mode 100644
index 0000000..648da8b
--- /dev/null
+++ b/WebCore/storage/IDBErrorEvent.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBErrorEvent_h
+#define IDBErrorEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBAny;
+class IDBDatabaseError;
+
+class IDBErrorEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBErrorEvent> create(PassRefPtr<IDBAny> source, const IDBDatabaseError&);
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBErrorEvent();
+
+ unsigned short code() const { return m_code; }
+ String message() { return m_message; }
+
+ virtual bool isIDBErrorEvent() const { return true; }
+
+private:
+ IDBErrorEvent(PassRefPtr<IDBAny> source, const IDBDatabaseError&);
+
+ unsigned short m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBEvent_h
diff --git a/WebCore/storage/IDBErrorEvent.idl b/WebCore/storage/IDBErrorEvent.idl
new file mode 100644
index 0000000..5c58f6f
--- /dev/null
+++ b/WebCore/storage/IDBErrorEvent.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBErrorEvent : IDBEvent {
+ readonly attribute unsigned short code;
+ readonly attribute DOMString message;
+ };
+}
diff --git a/WebCore/storage/IDBEvent.cpp b/WebCore/storage/IDBEvent.cpp
new file mode 100644
index 0000000..f9f6060
--- /dev/null
+++ b/WebCore/storage/IDBEvent.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBAny.h"
+
+namespace WebCore {
+
+IDBEvent::IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source)
+ : Event(type, false, false)
+ , m_source(source)
+{
+}
+
+IDBEvent::~IDBEvent()
+{
+}
+
+PassRefPtr<IDBAny> IDBEvent::source()
+{
+ return m_source;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBEvent.h b/WebCore/storage/IDBEvent.h
new file mode 100644
index 0000000..c44e449
--- /dev/null
+++ b/WebCore/storage/IDBEvent.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBEvent_h
+#define IDBEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "Event.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBAny;
+
+class IDBEvent : public Event {
+public:
+ virtual ~IDBEvent();
+
+ PassRefPtr<IDBAny> source();
+
+protected:
+ IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source);
+
+private:
+ RefPtr<IDBAny> m_source;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBEvent_h
diff --git a/WebCore/storage/IDBEvent.idl b/WebCore/storage/IDBEvent.idl
new file mode 100644
index 0000000..4dd552e
--- /dev/null
+++ b/WebCore/storage/IDBEvent.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBEvent : Event {
+ readonly attribute IDBAny source;
+ };
+}
diff --git a/WebCore/storage/IDBIndex.h b/WebCore/storage/IDBIndex.h
new file mode 100644
index 0000000..d0e8cab
--- /dev/null
+++ b/WebCore/storage/IDBIndex.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBIndex_h
+#define IDBIndex_h
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBIndex : public ThreadSafeShared<IDBIndex> {
+public:
+ virtual ~IDBIndex() { }
+
+ virtual String name() = 0;
+ virtual String keyPath() = 0;
+ virtual bool unique() = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndex_h
diff --git a/WebCore/storage/IDBIndexImpl.cpp b/WebCore/storage/IDBIndexImpl.cpp
new file mode 100644
index 0000000..f78939a
--- /dev/null
+++ b/WebCore/storage/IDBIndexImpl.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBIndexImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBIndexImpl::IDBIndexImpl(const String& name, const String& keyPath, bool unique)
+ : m_name(name)
+ , m_keyPath(keyPath)
+ , m_unique(unique)
+{
+}
+
+IDBIndexImpl::~IDBIndexImpl()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBIndexImpl.h b/WebCore/storage/IDBIndexImpl.h
new file mode 100644
index 0000000..b0034d5
--- /dev/null
+++ b/WebCore/storage/IDBIndexImpl.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBIndexImpl_h
+#define IDBIndexImpl_h
+
+#include "IDBIndex.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBIndexImpl : public IDBIndex {
+public:
+ static PassRefPtr<IDBIndex> create(const String& name, const String& keyPath, bool unique)
+ {
+ return adoptRef(new IDBIndexImpl(name, keyPath, unique));
+ }
+ virtual ~IDBIndexImpl();
+
+ // Implements IDBIndex
+ virtual String name() { return m_name; }
+ virtual String keyPath() { return m_keyPath; }
+ virtual bool unique() { return m_unique; }
+
+private:
+ IDBIndexImpl(const String& name, const String& keyPath, bool unique);
+
+ String m_name;
+ String m_keyPath;
+ bool m_unique;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndexImpl_h
diff --git a/WebCore/storage/IDBIndexRequest.cpp b/WebCore/storage/IDBIndexRequest.cpp
new file mode 100644
index 0000000..30aee4b
--- /dev/null
+++ b/WebCore/storage/IDBIndexRequest.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBIndexRequest.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBIndexRequest::IDBIndexRequest(PassRefPtr<IDBIndex> idbIndex)
+ : m_idbIndex(idbIndex)
+{
+}
+
+IDBIndexRequest::~IDBIndexRequest()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBIndexRequest.h b/WebCore/storage/IDBIndexRequest.h
new file mode 100644
index 0000000..ce6fc57
--- /dev/null
+++ b/WebCore/storage/IDBIndexRequest.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBIndexRequest_h
+#define IDBIndexRequest_h
+
+#include "IDBIndex.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBIndexRequest : public RefCounted<IDBIndexRequest> {
+public:
+ static PassRefPtr<IDBIndexRequest> create(PassRefPtr<IDBIndex> idbIndex)
+ {
+ return adoptRef(new IDBIndexRequest(idbIndex));
+ }
+ ~IDBIndexRequest();
+
+ // Implement the IDL
+ String name() const { return m_idbIndex->name(); }
+ String keyPath() const { return m_idbIndex->keyPath(); }
+ bool unique() const { return m_idbIndex->unique(); }
+
+private:
+ IDBIndexRequest(PassRefPtr<IDBIndex>);
+
+ RefPtr<IDBIndex> m_idbIndex;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndexRequest_h
diff --git a/WebCore/storage/IDBIndexRequest.idl b/WebCore/storage/IDBIndexRequest.idl
new file mode 100644
index 0000000..ad35f52
--- /dev/null
+++ b/WebCore/storage/IDBIndexRequest.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBIndexRequest {
+ // FIXME: Complete this file.
+
+ readonly attribute DOMString name;
+ readonly attribute DOMString keyPath;
+ readonly attribute boolean unique;
+ };
+
+}
diff --git a/WebCore/storage/IDBKey.cpp b/WebCore/storage/IDBKey.cpp
new file mode 100644
index 0000000..8ec5dfd
--- /dev/null
+++ b/WebCore/storage/IDBKey.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBKey.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBKey::IDBKey()
+ : m_type(NullType)
+{
+}
+
+IDBKey::IDBKey(int32_t number)
+ : m_type(NumberType)
+ , m_number(number)
+{
+}
+
+IDBKey::IDBKey(const String& string)
+ : m_type(StringType)
+ , m_string(string)
+{
+}
+
+IDBKey::~IDBKey()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBKey.h b/WebCore/storage/IDBKey.h
new file mode 100644
index 0000000..a84ea6a
--- /dev/null
+++ b/WebCore/storage/IDBKey.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBKey_h
+#define IDBKey_h
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+// FIXME: Add dates.
+class IDBKey : public RefCounted<IDBKey> {
+public:
+ static PassRefPtr<IDBKey> create()
+ {
+ return adoptRef(new IDBKey());
+ }
+ static PassRefPtr<IDBKey> create(int32_t number)
+ {
+ return adoptRef(new IDBKey(number));
+ }
+ static PassRefPtr<IDBKey> create(const String& string)
+ {
+ return adoptRef(new IDBKey(string));
+ }
+ ~IDBKey();
+
+ // In order of the least to the highest precedent in terms of sort order.
+ enum Type {
+ NullType = 0,
+ StringType,
+ NumberType
+ };
+
+ Type type() const { return m_type; }
+
+ const String& string() const
+ {
+ ASSERT(m_type == StringType);
+ return m_string;
+ }
+
+ int32_t number() const
+ {
+ ASSERT(m_type == NumberType);
+ return m_number;
+ }
+
+private:
+ IDBKey();
+ explicit IDBKey(int32_t);
+ explicit IDBKey(const String&);
+
+ Type m_type;
+ String m_string;
+ int32_t m_number;
+};
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBKey_h
diff --git a/WebCore/storage/IDBKey.idl b/WebCore/storage/IDBKey.idl
new file mode 100644
index 0000000..04995f3
--- /dev/null
+++ b/WebCore/storage/IDBKey.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE,
+ CustomToJS
+ ] IDBKey {
+ // This space is intentionally left blank.
+ };
+}
diff --git a/WebCore/storage/IDBKeyRange.cpp b/WebCore/storage/IDBKeyRange.cpp
new file mode 100644
index 0000000..dfcae19
--- /dev/null
+++ b/WebCore/storage/IDBKeyRange.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBKeyRange.h"
+
+#include "IDBKey.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBKeyRange::IDBKeyRange(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags)
+ : m_left(left)
+ , m_right(right)
+ , m_flags(flags)
+{
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::only(PassRefPtr<IDBKey> prpValue)
+{
+ RefPtr<IDBKey> value = prpValue;
+ return IDBKeyRange::create(value, value, IDBKeyRange::SINGLE);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::leftBound(PassRefPtr<IDBKey> bound, bool open)
+{
+ return IDBKeyRange::create(bound, IDBKey::create(), open ? IDBKeyRange::LEFT_OPEN : IDBKeyRange::LEFT_BOUND);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::rightBound(PassRefPtr<IDBKey> bound, bool open)
+{
+ return IDBKeyRange::create(IDBKey::create(), bound, open ? IDBKeyRange::RIGHT_OPEN : IDBKeyRange::RIGHT_BOUND);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::bound(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, bool openLeft, bool openRight)
+{
+ unsigned short flags = openLeft ? IDBKeyRange::LEFT_OPEN : IDBKeyRange::LEFT_BOUND;
+ flags |= openRight ? IDBKeyRange::RIGHT_OPEN : IDBKeyRange::RIGHT_BOUND;
+ return IDBKeyRange::create(left, right, flags);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBKeyRange.h b/WebCore/storage/IDBKeyRange.h
new file mode 100644
index 0000000..9ce07af
--- /dev/null
+++ b/WebCore/storage/IDBKeyRange.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBKeyRange_h
+#define IDBKeyRange_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBKey.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class IDBKeyRange : public RefCounted<IDBKeyRange> {
+public:
+ // Keep in sync with what's in the .idl file.
+ enum Flags {
+ SINGLE = 0,
+ LEFT_OPEN = 1,
+ RIGHT_OPEN = 2,
+ LEFT_BOUND = 4,
+ RIGHT_BOUND = 8,
+ };
+
+ static PassRefPtr<IDBKeyRange> create(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags)
+ {
+ return adoptRef(new IDBKeyRange(left, right, flags));
+ }
+ ~IDBKeyRange() { }
+
+
+ PassRefPtr<IDBKey> left() const { return m_left; }
+ PassRefPtr<IDBKey> right() const { return m_right; }
+ unsigned short flags() const { return m_flags; }
+
+ static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value);
+ static PassRefPtr<IDBKeyRange> leftBound(PassRefPtr<IDBKey> bound, bool open = false);
+ static PassRefPtr<IDBKeyRange> rightBound(PassRefPtr<IDBKey> bound, bool open = false);
+ static PassRefPtr<IDBKeyRange> bound(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, bool openLeft = false, bool openRight = false);
+private:
+ IDBKeyRange(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags);
+
+ RefPtr<IDBKey> m_left;
+ RefPtr<IDBKey> m_right;
+ unsigned short m_flags;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBKeyRange_h
diff --git a/WebCore/storage/IDBKeyRange.idl b/WebCore/storage/IDBKeyRange.idl
new file mode 100644
index 0000000..6daaec1
--- /dev/null
+++ b/WebCore/storage/IDBKeyRange.idl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBKeyRange {
+ // Keep in sync with what's in the .h file.
+ const unsigned short SINGLE = 0;
+ const unsigned short LEFT_OPEN = 1;
+ const unsigned short RIGHT_OPEN = 2;
+ const unsigned short LEFT_BOUND = 4;
+ const unsigned short RIGHT_BOUND = 8;
+
+ readonly attribute IDBKey left;
+ readonly attribute IDBKey right;
+ readonly attribute unsigned short flags;
+
+ IDBKeyRange only(in IDBKey value);
+ IDBKeyRange leftBound(in IDBKey bound, in [Optional] boolean open);
+ IDBKeyRange rightBound(in IDBKey bound, in [Optional] boolean open);
+ IDBKeyRange bound(in IDBKey left, in IDBKey right, in [Optional] boolean openLeft, in [Optional] boolean openRight);
+ };
+
+}
diff --git a/WebCore/storage/IDBKeyTree.h b/WebCore/storage/IDBKeyTree.h
new file mode 100644
index 0000000..70d6f83
--- /dev/null
+++ b/WebCore/storage/IDBKeyTree.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBKeyTree_h
+#define IDBKeyTree_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBKey.h"
+#include <wtf/AVLTree.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+template <typename ValueType>
+class IDBKeyTree : public RefCounted<IDBKeyTree<ValueType> > {
+public:
+ static PassRefPtr<IDBKeyTree> create()
+ {
+ return adoptRef(new IDBKeyTree());
+ }
+ ~IDBKeyTree();
+
+ ValueType* get(IDBKey* key);
+ void put(IDBKey* key, ValueType* value);
+ void remove(IDBKey* key);
+
+private:
+ struct TreeNode {
+ RefPtr<ValueType> value;
+ RefPtr<IDBKey> key;
+
+ TreeNode* less;
+ TreeNode* greater;
+ int balanceFactor;
+ };
+
+ struct AVLTreeAbstractor {
+ typedef TreeNode* handle;
+ typedef size_t size;
+ typedef IDBKey* key;
+
+ handle get_less(handle h) { return h->less; }
+ void set_less(handle h, handle lh) { h->less = lh; }
+ handle get_greater(handle h) { return h->greater; }
+ void set_greater(handle h, handle gh) { h->greater = gh; }
+ int get_balance_factor(handle h) { return h->balanceFactor; }
+ void set_balance_factor(handle h, int bf) { h->balanceFactor = bf; }
+
+ static handle null() { return 0; }
+
+ int compare_key_key(key va, key vb);
+ int compare_key_node(key k, handle h) { return compare_key_key(k, h->key.get()); }
+ int compare_node_node(handle h1, handle h2) { return compare_key_key(h1->key.get(), h2->key.get()); }
+ };
+
+ IDBKeyTree();
+
+ typedef WTF::AVLTree<AVLTreeAbstractor> TreeType;
+ TreeType m_tree;
+};
+
+template <typename ValueType>
+IDBKeyTree<ValueType>::IDBKeyTree()
+{
+}
+
+template <typename ValueType>
+IDBKeyTree<ValueType>::~IDBKeyTree()
+{
+ typename TreeType::Iterator iter;
+ iter.start_iter_least(m_tree);
+ for (; *iter; ++iter)
+ delete *iter;
+ m_tree.purge();
+}
+
+template <typename ValueType>
+int IDBKeyTree<ValueType>::AVLTreeAbstractor::compare_key_key(key va, key vb)
+{
+ if (va->type() != vb->type())
+ return vb->type() - va->type();
+
+ switch (va->type()) {
+ case IDBKey::NullType:
+ return 0;
+ case IDBKey::NumberType:
+ return vb->number() - va->number();
+ case IDBKey::StringType:
+ return codePointCompare(va->string(), vb->string());
+ // FIXME: Handle dates. Oh, and test this thoroughly.
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+template <typename ValueType>
+ValueType* IDBKeyTree<ValueType>::get(IDBKey* key)
+{
+ TreeNode* node = m_tree.search(key);
+ if (!node)
+ return 0;
+ return node->value.get();
+}
+
+template <typename ValueType>
+void IDBKeyTree<ValueType>::put(IDBKey* key, ValueType* value)
+{
+ TreeNode* node = m_tree.search(key);
+ if (!node) {
+ node = new TreeNode();
+ node->key = key;
+ m_tree.insert(node);
+ }
+ node->value = value;
+}
+
+template <typename ValueType>
+void IDBKeyTree<ValueType>::remove(IDBKey* key)
+{
+ TreeNode* node = m_tree.remove(key);
+ if (node)
+ delete node;
+}
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBKeyTree_h
diff --git a/WebCore/storage/IDBObjectStore.h b/WebCore/storage/IDBObjectStore.h
new file mode 100644
index 0000000..e78e62a
--- /dev/null
+++ b/WebCore/storage/IDBObjectStore.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBObjectStore_h
+#define IDBObjectStore_h
+
+#include "PlatformString.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+class IDBCallbacks;
+class IDBIndex;
+class IDBKey;
+class SerializedScriptValue;
+
+class IDBObjectStore : public ThreadSafeShared<IDBObjectStore> {
+public:
+ virtual ~IDBObjectStore() { }
+
+ virtual String name() const = 0;
+ virtual String keyPath() const = 0;
+ virtual PassRefPtr<DOMStringList> indexNames() const = 0;
+
+ virtual void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0;
+ virtual void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>) = 0;
+ virtual void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0;
+
+ virtual void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>) = 0;
+ virtual PassRefPtr<IDBIndex> index(const String& name) = 0;
+ virtual void removeIndex(const String& name, PassRefPtr<IDBCallbacks>) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStore_h
+
diff --git a/WebCore/storage/IDBObjectStoreImpl.cpp b/WebCore/storage/IDBObjectStoreImpl.cpp
new file mode 100755
index 0000000..d678400
--- /dev/null
+++ b/WebCore/storage/IDBObjectStoreImpl.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBObjectStoreImpl.h"
+
+#include "DOMStringList.h"
+#include "IDBBindingUtilities.h"
+#include "IDBCallbacks.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndexImpl.h"
+#include "IDBKeyTree.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBObjectStoreImpl::~IDBObjectStoreImpl()
+{
+}
+
+IDBObjectStoreImpl::IDBObjectStoreImpl(const String& name, const String& keyPath, bool autoIncrement)
+ : m_name(name)
+ , m_keyPath(keyPath)
+ , m_autoIncrement(autoIncrement)
+ , m_tree(Tree::create())
+{
+}
+
+PassRefPtr<DOMStringList> IDBObjectStoreImpl::indexNames() const
+{
+ RefPtr<DOMStringList> indexNames = DOMStringList::create();
+ for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
+ indexNames->append(it->first);
+ return indexNames.release();
+}
+
+void IDBObjectStoreImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+ RefPtr<SerializedScriptValue> value = m_tree->get(key.get());
+ if (!value) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
+ return;
+ }
+ callbacks->onSuccess(value.get());
+}
+
+void IDBObjectStoreImpl::put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks)
+{
+ RefPtr<IDBKey> key = prpKey;
+
+ if (!m_keyPath.isNull()) {
+ if (key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath."));
+ return;
+ }
+ ASSERT_NOT_REACHED();
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "FIXME: keyPath not yet supported."));
+ return;
+ }
+
+ if (!key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied."));
+ return;
+ }
+
+ if (addOnly && m_tree->get(key.get())) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
+ return;
+ }
+
+ m_tree->put(key.get(), value.get());
+ callbacks->onSuccess(key.get());
+}
+
+void IDBObjectStoreImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+ m_tree->remove(key.get());
+ callbacks->onSuccess();
+}
+
+void IDBObjectStoreImpl::createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks> callbacks)
+{
+ if (m_indexes.contains(name)) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Index name already exists."));
+ return;
+ }
+
+ RefPtr<IDBIndex> index = IDBIndexImpl::create(name, keyPath, unique);
+ ASSERT(index->name() == name);
+ m_indexes.set(name, index);
+ callbacks->onSuccess(index.release());
+}
+
+PassRefPtr<IDBIndex> IDBObjectStoreImpl::index(const String& name)
+{
+ return m_indexes.get(name);
+}
+
+void IDBObjectStoreImpl::removeIndex(const String& name, PassRefPtr<IDBCallbacks> callbacks)
+{
+ if (!m_indexes.contains(name)) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Index name does not exist."));
+ return;
+ }
+
+ m_indexes.remove(name);
+ callbacks->onSuccess();
+}
+
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBObjectStoreImpl.h b/WebCore/storage/IDBObjectStoreImpl.h
new file mode 100644
index 0000000..c4d2eb8
--- /dev/null
+++ b/WebCore/storage/IDBObjectStoreImpl.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBObjectStoreImpl_h
+#define IDBObjectStoreImpl_h
+
+#include "IDBObjectStore.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+template <typename ValueType> class IDBKeyTree;
+
+class IDBObjectStoreImpl : public IDBObjectStore {
+public:
+ static PassRefPtr<IDBObjectStore> create(const String& name, const String& keyPath, bool autoIncrement)
+ {
+ return adoptRef(new IDBObjectStoreImpl(name, keyPath, autoIncrement));
+ }
+ ~IDBObjectStoreImpl();
+
+ String name() const { return m_name; }
+ String keyPath() const { return m_keyPath; }
+ PassRefPtr<DOMStringList> indexNames() const;
+
+ void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>);
+ void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+
+ void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>);
+ PassRefPtr<IDBIndex> index(const String& name);
+ void removeIndex(const String& name, PassRefPtr<IDBCallbacks>);
+
+private:
+ IDBObjectStoreImpl(const String& name, const String& keyPath, bool autoIncrement);
+
+ String m_name;
+ String m_keyPath;
+ bool m_autoIncrement;
+
+ typedef HashMap<String, RefPtr<IDBIndex> > IndexMap;
+ IndexMap m_indexes;
+
+ typedef IDBKeyTree<SerializedScriptValue> Tree;
+ RefPtr<Tree> m_tree;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStoreImpl_h
diff --git a/WebCore/storage/IDBObjectStoreRequest.cpp b/WebCore/storage/IDBObjectStoreRequest.cpp
new file mode 100644
index 0000000..3e095c1
--- /dev/null
+++ b/WebCore/storage/IDBObjectStoreRequest.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBObjectStoreRequest.h"
+
+#include "DOMStringList.h"
+#include "IDBAny.h"
+#include "IDBIndexRequest.h"
+#include "IDBKey.h"
+#include "SerializedScriptValue.h"
+#include <wtf/UnusedParam.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBObjectStoreRequest::IDBObjectStoreRequest(PassRefPtr<IDBObjectStore> idbObjectStore)
+ : m_objectStore(idbObjectStore)
+{
+ // We pass a reference to this object before it can be adopted.
+ relaxAdoptionRequirement();
+}
+
+String IDBObjectStoreRequest::name() const
+{
+ return m_objectStore->name();
+}
+
+String IDBObjectStoreRequest::keyPath() const
+{
+ return m_objectStore->keyPath();
+}
+
+PassRefPtr<DOMStringList> IDBObjectStoreRequest::indexNames() const
+{
+ return m_objectStore->indexNames();
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->get(key, request);
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->put(value, key, true, request);
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->put(value, key, false, request);
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::remove(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->remove(key, request);
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::createIndex(ScriptExecutionContext* context, const String& name, const String& keyPath, bool unique)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->createIndex(name, keyPath, unique, request);
+ return request;
+}
+
+PassRefPtr<IDBIndexRequest> IDBObjectStoreRequest::index(const String& name)
+{
+ RefPtr<IDBIndex> index = m_objectStore->index(name);
+ ASSERT(index); // FIXME: If this is null, we should raise a NOT_FOUND_ERR.
+ return IDBIndexRequest::create(index.release());
+}
+
+PassRefPtr<IDBRequest> IDBObjectStoreRequest::removeIndex(ScriptExecutionContext* context, const String& name)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+ m_objectStore->removeIndex(name, request);
+ return request;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBObjectStoreRequest.h b/WebCore/storage/IDBObjectStoreRequest.h
new file mode 100644
index 0000000..86f64d6
--- /dev/null
+++ b/WebCore/storage/IDBObjectStoreRequest.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBObjectStoreRequest_h
+#define IDBObjectStoreRequest_h
+
+#include "IDBObjectStore.h"
+#include "IDBRequest.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+class IDBAny;
+class IDBIndexRequest;
+class IDBKey;
+class SerializedScriptValue;
+
+class IDBObjectStoreRequest : public RefCounted<IDBObjectStoreRequest> {
+public:
+ static PassRefPtr<IDBObjectStoreRequest> create(PassRefPtr<IDBObjectStore> idbObjectStore)
+ {
+ return adoptRef(new IDBObjectStoreRequest(idbObjectStore));
+ }
+ ~IDBObjectStoreRequest() { }
+
+ String name() const;
+ String keyPath() const;
+ PassRefPtr<DOMStringList> indexNames() const;
+
+ PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey> key);
+ PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0);
+ PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0);
+ PassRefPtr<IDBRequest> remove(ScriptExecutionContext*, PassRefPtr<IDBKey> key);
+
+ PassRefPtr<IDBRequest> createIndex(ScriptExecutionContext*, const String& name, const String& keyPath, bool unique = false);
+ PassRefPtr<IDBIndexRequest> index(const String& name);
+ PassRefPtr<IDBRequest> removeIndex(ScriptExecutionContext*, const String& name);
+
+private:
+ IDBObjectStoreRequest(PassRefPtr<IDBObjectStore>);
+
+ RefPtr<IDBObjectStore> m_objectStore;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStoreRequest_h
+
diff --git a/WebCore/storage/IDBObjectStoreRequest.idl b/WebCore/storage/IDBObjectStoreRequest.idl
new file mode 100644
index 0000000..a816b73
--- /dev/null
+++ b/WebCore/storage/IDBObjectStoreRequest.idl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBObjectStoreRequest {
+ [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key);
+ // FIXME: Come to concensus re getAll.
+ // FIXME: SerializedScriptValue raises an exception if you pass in something that can't be serialized.
+ // We need to instead "raise" this error via an error callback.
+ [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key);
+ [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key);
+ [CallWith=ScriptExecutionContext] IDBRequest remove(in IDBKey key);
+ // FIXME: write openCursor
+ [CallWith=ScriptExecutionContext] IDBRequest createIndex(in DOMString name, in [ConvertNullToNullString] DOMString keyPath, in [Optional] boolean unique);
+ // FIXME: This needs to raise an IDBDatabaseException on errors.
+ IDBIndexRequest index(in DOMString name);
+ [CallWith=ScriptExecutionContext] IDBRequest removeIndex(in DOMString name);
+
+ readonly attribute DOMString name;
+ readonly attribute [ConvertNullStringTo=Null] DOMString keyPath;
+ readonly attribute DOMStringList indexNames;
+ };
+}
diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp
index 1a20499..78dd15a 100644
--- a/WebCore/storage/IDBRequest.cpp
+++ b/WebCore/storage/IDBRequest.cpp
@@ -25,40 +25,164 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#include "config.h"
#include "IDBRequest.h"
#if ENABLE(INDEXED_DATABASE)
-#include "IDBDatabaseError.h"
-#include "SerializedScriptValue.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "IDBDatabaseRequest.h"
+#include "IDBIndexRequest.h"
+#include "IDBErrorEvent.h"
+#include "IDBObjectStoreRequest.h"
+#include "IDBSuccessEvent.h"
+#include "ScriptExecutionContext.h"
namespace WebCore {
-IDBRequest::IDBRequest(ScriptExecutionContext* context)
+IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source)
: ActiveDOMObject(context, this)
+ , m_source(source)
+ , m_result(IDBAny::create())
+ , m_timer(this, &IDBRequest::timerFired)
+ , m_stopped(false)
+ , m_aborted(false)
+ , m_readyState(INITIAL)
{
}
IDBRequest::~IDBRequest()
{
+ if (m_readyState != DONE)
+ abort();
+}
+
+void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
+{
+ onEventCommon();
+ m_error = error;
+}
+
+void IDBRequest::onSuccess()
+{
+ onEventCommon();
+ m_result->set();
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBDatabase> idbDatabase)
+{
+ onEventCommon();
+ m_result->set(IDBDatabaseRequest::create(idbDatabase));
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBIndex> idbIndex)
+{
+ onEventCommon();
+ m_result->set(IDBIndexRequest::create(idbIndex));
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
+{
+ onEventCommon();
+ m_result->set(idbKey);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBObjectStore> idbObjectStore)
+{
+ onEventCommon();
+ m_result->set(IDBObjectStoreRequest::create(idbObjectStore));
+}
+
+void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
+{
+ onEventCommon();
+ m_result->set(serializedScriptValue);
}
void IDBRequest::abort()
{
+ m_timer.stop();
+ m_aborted = true;
+ // FIXME: This should cancel any pending work being done in the backend.
+}
+
+ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
+}
+
+void IDBRequest::stop()
+{
+ abort();
+ m_selfRef = 0; // Could trigger a delete.
+}
+
+void IDBRequest::suspend()
+{
+ m_timer.stop();
+ m_stopped = true;
+}
+
+void IDBRequest::resume()
+{
+ m_stopped = false;
+ // We only hold our self ref when we're waiting to dispatch an event.
+ if (m_selfRef && !m_aborted)
+ m_timer.startOneShot(0);
}
EventTargetData* IDBRequest::eventTargetData()
{
- return 0;
+ return &m_eventTargetData;
}
EventTargetData* IDBRequest::ensureEventTargetData()
{
- return 0;
+ return &m_eventTargetData;
}
-} // namespace WebCore
+void IDBRequest::timerFired(Timer<IDBRequest>*)
+{
+ ASSERT(m_readyState == DONE);
+ ASSERT(m_selfRef);
+ ASSERT(!m_stopped);
+ ASSERT(!m_aborted);
+
+ // We need to keep self-referencing ourself, otherwise it's possible we'll be deleted.
+ // But in some cases, suspend() could be called while we're dispatching an event, so we
+ // need to make sure that resume() doesn't re-start the timer based on m_selfRef being set.
+ RefPtr<IDBRequest> selfRef = m_selfRef.release();
-#endif // ENABLE(INDEXED_DATABASE)
+ if (m_error) {
+ ASSERT(m_result->type() == IDBAny::UndefinedType);
+ dispatchEvent(IDBErrorEvent::create(m_source, *m_error));
+ } else {
+ ASSERT(m_result->type() != IDBAny::UndefinedType);
+ dispatchEvent(IDBSuccessEvent::create(m_source, m_result));
+ }
+}
+
+void IDBRequest::onEventCommon()
+{
+ ASSERT(m_readyState < DONE);
+ ASSERT(m_result->type() == IDBAny::UndefinedType);
+ ASSERT(!m_error);
+ ASSERT(!m_selfRef);
+ ASSERT(!m_timer.isActive());
+
+ if (m_aborted)
+ return;
+
+ m_readyState = DONE;
+ m_selfRef = this;
+ if (!m_stopped)
+ m_timer.startOneShot(0);
+}
+
+} // namespace WebCore
+#endif
diff --git a/WebCore/storage/IDBRequest.h b/WebCore/storage/IDBRequest.h
index 5f00aa8..c763d96 100644
--- a/WebCore/storage/IDBRequest.h
+++ b/WebCore/storage/IDBRequest.h
@@ -25,64 +25,92 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#ifndef IDBRequest_h
#define IDBRequest_h
+#if ENABLE(INDEXED_DATABASE)
+
#include "ActiveDOMObject.h"
+#include "EventListener.h"
+#include "EventNames.h"
#include "EventTarget.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-
-#if ENABLE(INDEXED_DATABASE)
+#include "IDBAny.h"
+#include "IDBCallbacks.h"
+#include "Timer.h"
namespace WebCore {
-class IDBDatabaseError;
-class SerializedScriptValue;
+class IDBDatabaseRequest;
-class IDBRequest : public RefCounted<IDBRequest>, public ActiveDOMObject, public EventTarget {
+class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
public:
- static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context)
- {
- return adoptRef(new IDBRequest(context));
- }
- ~IDBRequest();
+ static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source) { return adoptRef(new IDBRequest(context, source)); }
+ virtual ~IDBRequest();
+ // Defined in the IDL
void abort();
+ enum ReadyState {
+ INITIAL = 0,
+ LOADING = 1,
+ DONE = 2
+ };
unsigned short readyState() const { return m_readyState; }
- IDBDatabaseError* error() const { return m_error.get(); }
- SerializedScriptValue* result() const { return m_result.get(); }
-
+ PassRefPtr<IDBDatabaseError> error() const { return m_error; }
+ PassRefPtr<IDBAny> result() { return m_result; }
DEFINE_ATTRIBUTE_EVENT_LISTENER(success);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
- using RefCounted<IDBRequest>::ref;
- using RefCounted<IDBRequest>::deref;
+ // IDBCallbacks
+ virtual void onError(PassRefPtr<IDBDatabaseError>);
+ virtual void onSuccess(); // For "null".
+ virtual void onSuccess(PassRefPtr<IDBDatabase>);
+ virtual void onSuccess(PassRefPtr<IDBIndex>);
+ virtual void onSuccess(PassRefPtr<IDBKey>);
+ virtual void onSuccess(PassRefPtr<IDBObjectStore>);
+ virtual void onSuccess(PassRefPtr<SerializedScriptValue>);
- // EventTarget interface
- virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); }
+ // EventTarget
virtual IDBRequest* toIDBRequest() { return this; }
+ // ActiveDOMObject
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+ virtual void stop();
+ virtual void suspend();
+ virtual void resume();
+
+ using RefCounted<IDBCallbacks>::ref;
+ using RefCounted<IDBCallbacks>::deref;
+
private:
- explicit IDBRequest(ScriptExecutionContext* context);
+ IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source);
+
+ void timerFired(Timer<IDBRequest>*);
+ void onEventCommon();
- // EventTarget interface
+ // EventTarget
virtual void refEventTarget() { ref(); }
virtual void derefEventTarget() { deref(); }
virtual EventTargetData* eventTargetData();
virtual EventTargetData* ensureEventTargetData();
- unsigned short m_readyState;
+ RefPtr<IDBAny> m_source;
+
+ RefPtr<IDBAny> m_result;
RefPtr<IDBDatabaseError> m_error;
- RefPtr<SerializedScriptValue> m_result;
+ // Used to fire events asynchronously.
+ Timer<IDBRequest> m_timer;
+ RefPtr<IDBRequest> m_selfRef; // This is set to us iff there's an event pending.
+
+ bool m_stopped;
+ bool m_aborted;
+ ReadyState m_readyState;
EventTargetData m_eventTargetData;
};
} // namespace WebCore
-#endif
+#endif // ENABLE(INDEXED_DATABASE)
#endif // IDBRequest_h
-
diff --git a/WebCore/storage/IDBRequest.idl b/WebCore/storage/IDBRequest.idl
index b34184c..9d7e0e4 100644
--- a/WebCore/storage/IDBRequest.idl
+++ b/WebCore/storage/IDBRequest.idl
@@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
module storage {
interface [
@@ -32,14 +33,29 @@ module storage {
EventTarget
] IDBRequest {
void abort();
+
+ // States
const unsigned short INITIAL = 0;
const unsigned short LOADING = 1;
const unsigned short DONE = 2;
readonly attribute unsigned short readyState;
+
+ // Possible results
readonly attribute IDBDatabaseError error;
- readonly attribute [CustomGetter] any result;
+ readonly attribute IDBAny result;
+
+ // Events
attribute EventListener onsuccess;
attribute EventListener onerror;
- };
+ // EventTarget interface
+ void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+ };
}
diff --git a/WebCore/storage/IDBSuccessEvent.cpp b/WebCore/storage/IDBSuccessEvent.cpp
new file mode 100644
index 0000000..2dcd964
--- /dev/null
+++ b/WebCore/storage/IDBSuccessEvent.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBSuccessEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBSuccessEvent> IDBSuccessEvent::create(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result)
+{
+ return adoptRef(new IDBSuccessEvent(source, result));
+}
+
+IDBSuccessEvent::IDBSuccessEvent(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result)
+ : IDBEvent(eventNames().successEvent, source)
+ , m_result(result)
+{
+}
+
+IDBSuccessEvent::~IDBSuccessEvent()
+{
+}
+
+PassRefPtr<IDBAny> IDBSuccessEvent::result()
+{
+ return m_result;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBSuccessEvent.h b/WebCore/storage/IDBSuccessEvent.h
new file mode 100644
index 0000000..5be660a
--- /dev/null
+++ b/WebCore/storage/IDBSuccessEvent.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBSuccessEvent_h
+#define IDBSuccessEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBAny;
+
+class IDBSuccessEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBSuccessEvent> create(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result);
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBSuccessEvent();
+
+ PassRefPtr<IDBAny> result();
+
+ virtual bool isIDBSuccessEvent() const { return true; }
+
+private:
+ IDBSuccessEvent(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result);
+
+ RefPtr<IDBAny> m_result;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBEvent_h
diff --git a/WebCore/storage/IDBSuccessEvent.idl b/WebCore/storage/IDBSuccessEvent.idl
new file mode 100644
index 0000000..b4ea7d2
--- /dev/null
+++ b/WebCore/storage/IDBSuccessEvent.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBSuccessEvent : IDBEvent {
+ readonly attribute IDBAny result;
+ };
+}
diff --git a/WebCore/storage/IndexedDatabase.cpp b/WebCore/storage/IndexedDatabase.cpp
new file mode 100644
index 0000000..a20974b
--- /dev/null
+++ b/WebCore/storage/IndexedDatabase.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IndexedDatabase.h"
+
+#include "IndexedDatabaseImpl.h"
+
+#if PLATFORM(CHROMIUM)
+#error "Chromium should not compile this file and instead define its own version of this factory that navigates the multi-process boundry."
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+PassRefPtr<IndexedDatabase> IndexedDatabase::create()
+{
+ return IndexedDatabaseImpl::create();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/WebCore/storage/IndexedDatabase.h b/WebCore/storage/IndexedDatabase.h
new file mode 100644
index 0000000..e6abf4a
--- /dev/null
+++ b/WebCore/storage/IndexedDatabase.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IndexedDatabase_h
+#define IndexedDatabase_h
+
+#include "ExceptionCode.h"
+#include "IDBCallbacks.h"
+#include "PlatformString.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class Frame;
+class IDBDatabase;
+class SecurityOrigin;
+
+// This class is shared by IndexedDatabaseRequest (async) and IndexedDatabaseSync (sync).
+// This is implemented by IndexedDatabaseImpl and optionally others (in order to proxy
+// calls across process barriers). All calls to these classes should be non-blocking and
+// trigger work on a background thread if necessary.
+class IndexedDatabase : public ThreadSafeShared<IndexedDatabase> {
+public:
+ static PassRefPtr<IndexedDatabase> create();
+ virtual ~IndexedDatabase() { }
+
+ virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IndexedDatabase_h
+
diff --git a/WebCore/storage/IndexedDatabaseImpl.cpp b/WebCore/storage/IndexedDatabaseImpl.cpp
new file mode 100644
index 0000000..e6af901
--- /dev/null
+++ b/WebCore/storage/IndexedDatabaseImpl.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IndexedDatabaseImpl.h"
+
+#include "IDBDatabaseImpl.h"
+#include "SecurityOrigin.h"
+#include <wtf/Threading.h>
+#include <wtf/UnusedParam.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+PassRefPtr<IndexedDatabaseImpl> IndexedDatabaseImpl::create()
+{
+ return adoptRef(new IndexedDatabaseImpl);
+}
+
+IndexedDatabaseImpl::IndexedDatabaseImpl()
+{
+}
+
+IndexedDatabaseImpl::~IndexedDatabaseImpl()
+{
+}
+
+void IndexedDatabaseImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin>, Frame*)
+{
+ RefPtr<IDBDatabase> database;
+ IDBDatabaseMap::iterator it = m_databaseMap.find(name);
+ if (it == m_databaseMap.end()) {
+ // FIXME: What should the version be? The spec doesn't define it yet.
+ database = IDBDatabaseImpl::create(name, description, "");
+ m_databaseMap.set(name, database);
+ } else
+ database = it->second;
+
+ callbacks->onSuccess(database.release());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/WebCore/storage/IndexedDatabaseImpl.h b/WebCore/storage/IndexedDatabaseImpl.h
new file mode 100644
index 0000000..b9520ee
--- /dev/null
+++ b/WebCore/storage/IndexedDatabaseImpl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IndexedDatabaseImpl_h
+#define IndexedDatabaseImpl_h
+
+#include "IndexedDatabase.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IndexedDatabaseImpl : public IndexedDatabase {
+public:
+ static PassRefPtr<IndexedDatabaseImpl> create();
+ virtual ~IndexedDatabaseImpl();
+
+ virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*);
+
+private:
+ IndexedDatabaseImpl();
+
+ typedef HashMap<String, RefPtr<IDBDatabase> > IDBDatabaseMap;
+ IDBDatabaseMap m_databaseMap;
+
+ // We only create one instance of this class at a time.
+ static IndexedDatabaseImpl* indexedDatabaseImpl;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IndexedDatabaseImpl_h
+
diff --git a/WebCore/storage/IndexedDatabaseRequest.cpp b/WebCore/storage/IndexedDatabaseRequest.cpp
index 827493b..c1c5515 100644
--- a/WebCore/storage/IndexedDatabaseRequest.cpp
+++ b/WebCore/storage/IndexedDatabaseRequest.cpp
@@ -25,29 +25,49 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#include "config.h"
#include "IndexedDatabaseRequest.h"
-#if ENABLE(INDEXED_DATABASE)
-
+#include "Document.h"
#include "ExceptionCode.h"
+#include "Frame.h"
+#include "IDBDatabase.h"
+#include "IDBKeyRange.h"
#include "IDBRequest.h"
+#include "IndexedDatabase.h"
+
+#if ENABLE(INDEXED_DATABASE)
namespace WebCore {
-IndexedDatabaseRequest::IndexedDatabaseRequest()
+IndexedDatabaseRequest::IndexedDatabaseRequest(IndexedDatabase* indexedDatabase)
+ : m_indexedDatabase(indexedDatabase)
{
+ // We pass a reference to this object before it can be adopted.
+ relaxAdoptionRequirement();
}
IndexedDatabaseRequest::~IndexedDatabaseRequest()
{
}
-void IndexedDatabaseRequest::open(const String& name, const String& description, bool modifyDatabase, ExceptionCode& exception)
+PassRefPtr<IDBRequest> IndexedDatabaseRequest::open(ScriptExecutionContext* context, const String& name, const String& description)
{
+ if (!context->isDocument()) {
+ // FIXME: make this work with workers.
+ return 0;
+ }
+
+ Document* document = static_cast<Document*>(context);
+ if (!document->frame())
+ return 0;
+
+ RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this));
+ m_indexedDatabase->open(name, description, request, document->securityOrigin(), document->frame());
+ return request;
}
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)
-
diff --git a/WebCore/storage/IndexedDatabaseRequest.h b/WebCore/storage/IndexedDatabaseRequest.h
index 74aada3..57f8a78 100644
--- a/WebCore/storage/IndexedDatabaseRequest.h
+++ b/WebCore/storage/IndexedDatabaseRequest.h
@@ -29,6 +29,7 @@
#define IndexedDatabaseRequest_h
#include "ExceptionCode.h"
+#include "IndexedDatabase.h"
#include "PlatformString.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -38,23 +39,26 @@
namespace WebCore {
+class IDBKey;
+class IDBKeyRange;
class IDBRequest;
+class IndexedDatabase;
+class ScriptExecutionContext;
class IndexedDatabaseRequest : public RefCounted<IndexedDatabaseRequest> {
public:
- static PassRefPtr<IndexedDatabaseRequest> create()
+ static PassRefPtr<IndexedDatabaseRequest> create(IndexedDatabase* indexedDatabase)
{
- return adoptRef(new IndexedDatabaseRequest());
+ return adoptRef(new IndexedDatabaseRequest(indexedDatabase));
}
~IndexedDatabaseRequest();
- IDBRequest* request() const { return m_request.get(); }
- void open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&);
+ PassRefPtr<IDBRequest> open(ScriptExecutionContext*, const String& name, const String& description);
private:
- IndexedDatabaseRequest();
+ IndexedDatabaseRequest(IndexedDatabase*);
- PassRefPtr<IDBRequest> m_request;
+ RefPtr<IndexedDatabase> m_indexedDatabase;
};
} // namespace WebCore
diff --git a/WebCore/storage/IndexedDatabaseRequest.idl b/WebCore/storage/IndexedDatabaseRequest.idl
index b1fc7da..e6ee446 100644
--- a/WebCore/storage/IndexedDatabaseRequest.idl
+++ b/WebCore/storage/IndexedDatabaseRequest.idl
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -25,14 +22,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
module storage {
interface [
Conditional=INDEXED_DATABASE
] IndexedDatabaseRequest {
- readonly attribute IDBRequest request;
- [Custom] void open(in DOMString name, in DOMString description, in optional boolean modifyDatabase)
- raises(IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest open(in DOMString name, in DOMString description);
};
}
diff --git a/WebCore/storage/LocalStorageTask.cpp b/WebCore/storage/LocalStorageTask.cpp
index 12cc083..d31c991 100644
--- a/WebCore/storage/LocalStorageTask.cpp
+++ b/WebCore/storage/LocalStorageTask.cpp
@@ -39,7 +39,7 @@ LocalStorageTask::LocalStorageTask(Type type, StorageAreaSync* area)
, m_thread(0)
{
ASSERT(m_area);
- ASSERT(m_type == AreaImport || m_type == AreaSync);
+ ASSERT(m_type == AreaImport || m_type == AreaSync || m_type == DeleteEmptyDatabase);
}
LocalStorageTask::LocalStorageTask(Type type, LocalStorageThread* thread)
@@ -64,6 +64,9 @@ void LocalStorageTask::performTask()
case AreaSync:
m_area->performSync();
break;
+ case DeleteEmptyDatabase:
+ m_area->deleteEmptyDatabase();
+ break;
case TerminateThread:
m_thread->performTerminate();
break;
diff --git a/WebCore/storage/LocalStorageTask.h b/WebCore/storage/LocalStorageTask.h
index dc3e7e2..8d53ce4 100644
--- a/WebCore/storage/LocalStorageTask.h
+++ b/WebCore/storage/LocalStorageTask.h
@@ -39,12 +39,13 @@ namespace WebCore {
// FIXME: Rename this class to StorageTask
class LocalStorageTask : public Noncopyable {
public:
- enum Type { AreaImport, AreaSync, TerminateThread };
+ enum Type { AreaImport, AreaSync, DeleteEmptyDatabase, TerminateThread };
~LocalStorageTask();
static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return new LocalStorageTask(AreaImport, area); }
static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return new LocalStorageTask(AreaSync, area); }
+ static PassOwnPtr<LocalStorageTask> createDeleteEmptyDatabase(StorageAreaSync* area) { return new LocalStorageTask(DeleteEmptyDatabase, area); }
static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return new LocalStorageTask(TerminateThread, thread); }
void performTask();
diff --git a/WebCore/storage/OriginQuotaManager.cpp b/WebCore/storage/OriginQuotaManager.cpp
index 30b3271..0f415c1 100644
--- a/WebCore/storage/OriginQuotaManager.cpp
+++ b/WebCore/storage/OriginQuotaManager.cpp
@@ -30,7 +30,7 @@
#if ENABLE(DATABASE)
-#include "Database.h"
+#include "AbstractDatabase.h"
#include "OriginUsageRecord.h"
namespace WebCore {
@@ -42,6 +42,18 @@ OriginQuotaManager::OriginQuotaManager()
{
}
+bool OriginQuotaManager::tryLock()
+{
+ bool locked = m_usageRecordGuard.tryLock();
+#ifndef NDEBUG
+ if (locked)
+ m_usageRecordGuardLocked = true;
+ else
+ ASSERT(m_usageRecordGuardLocked);
+#endif
+ return locked;
+}
+
void OriginQuotaManager::lock()
{
m_usageRecordGuard.lock();
@@ -63,7 +75,7 @@ void OriginQuotaManager::trackOrigin(PassRefPtr<SecurityOrigin> origin)
ASSERT(m_usageRecordGuardLocked);
ASSERT(!m_usageMap.contains(origin.get()));
- m_usageMap.set(origin, new OriginUsageRecord);
+ m_usageMap.set(origin->threadsafeCopy(), new OriginUsageRecord);
}
bool OriginQuotaManager::tracksOrigin(SecurityOrigin* origin) const
@@ -100,7 +112,7 @@ void OriginQuotaManager::removeOrigin(SecurityOrigin* origin)
}
}
-void OriginQuotaManager::markDatabase(Database* database)
+void OriginQuotaManager::markDatabase(AbstractDatabase* database)
{
ASSERT(database);
ASSERT(m_usageRecordGuardLocked);
diff --git a/WebCore/storage/OriginQuotaManager.h b/WebCore/storage/OriginQuotaManager.h
index 2e3615d..c904737 100644
--- a/WebCore/storage/OriginQuotaManager.h
+++ b/WebCore/storage/OriginQuotaManager.h
@@ -38,13 +38,14 @@
namespace WebCore {
-class Database;
+class AbstractDatabase;
class OriginUsageRecord;
class OriginQuotaManager : public Noncopyable {
public:
OriginQuotaManager();
+ bool tryLock();
void lock();
void unlock();
@@ -54,7 +55,7 @@ public:
void removeDatabase(SecurityOrigin*, const String& databaseIdentifier);
void removeOrigin(SecurityOrigin*);
- void markDatabase(Database*); // Mark dirtiness of a specific database.
+ void markDatabase(AbstractDatabase*); // Mark dirtiness of a specific database.
unsigned long long diskUsage(SecurityOrigin*) const;
private:
diff --git a/WebCore/storage/OriginUsageRecord.cpp b/WebCore/storage/OriginUsageRecord.cpp
index 684df53..8128a1b 100644
--- a/WebCore/storage/OriginUsageRecord.cpp
+++ b/WebCore/storage/OriginUsageRecord.cpp
@@ -42,8 +42,8 @@ OriginUsageRecord::OriginUsageRecord()
void OriginUsageRecord::addDatabase(const String& identifier, const String& fullPath)
{
ASSERT(!m_databaseMap.contains(identifier));
- ASSERT_ARG(identifier, identifier.impl()->refCount() == 1);
- ASSERT_ARG(fullPath, fullPath.impl()->refCount() == 1);
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef());
+ ASSERT_ARG(fullPath, fullPath.impl()->hasOneRef());
m_databaseMap.set(identifier, DatabaseEntry(fullPath));
m_unknownSet.add(identifier);
@@ -63,7 +63,7 @@ void OriginUsageRecord::removeDatabase(const String& identifier)
void OriginUsageRecord::markDatabase(const String& identifier)
{
ASSERT(m_databaseMap.contains(identifier));
- ASSERT_ARG(identifier, identifier.impl()->refCount() == 1);
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef());
m_unknownSet.add(identifier);
m_cachedDiskUsageIsValid = false;
diff --git a/WebCore/storage/SQLError.h b/WebCore/storage/SQLError.h
index 4414e6b..496145a 100644
--- a/WebCore/storage/SQLError.h
+++ b/WebCore/storage/SQLError.h
@@ -32,7 +32,7 @@
#if ENABLE(DATABASE)
#include "PlatformString.h"
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
@@ -43,6 +43,17 @@ public:
unsigned code() const { return m_code; }
String message() const { return m_message.threadsafeCopy(); }
+ enum SQLErrorCode {
+ UNKNOWN_ERR = 0,
+ DATABASE_ERR = 1,
+ VERSION_ERR = 2,
+ TOO_LARGE_ERR = 3,
+ QUOTA_ERR = 4,
+ SYNTAX_ERR = 5,
+ CONSTRAINT_ERR = 6,
+ TIMEOUT_ERR = 7
+ };
+
private:
SQLError(unsigned code, const String& message) : m_code(code), m_message(message.threadsafeCopy()) { }
unsigned m_code;
diff --git a/WebCore/storage/SQLError.idl b/WebCore/storage/SQLError.idl
index 503fe6f..87be8c7 100644
--- a/WebCore/storage/SQLError.idl
+++ b/WebCore/storage/SQLError.idl
@@ -30,9 +30,20 @@ module storage {
interface [
Conditional=DATABASE,
- OmitConstructor
+ OmitConstructor,
+ NoStaticTables
] SQLError {
readonly attribute unsigned long code;
readonly attribute DOMString message;
+
+ // SQLErrorCode: used only in the async DB API
+ const unsigned short UNKNOWN_ERR = 0;
+ const unsigned short DATABASE_ERR = 1;
+ const unsigned short VERSION_ERR = 2;
+ const unsigned short TOO_LARGE_ERR = 3;
+ const unsigned short QUOTA_ERR = 4;
+ const unsigned short SYNTAX_ERR = 5;
+ const unsigned short CONSTRAINT_ERR = 6;
+ const unsigned short TIMEOUT_ERR = 7;
};
}
diff --git a/WebCore/storage/SQLException.h b/WebCore/storage/SQLException.h
new file mode 100644
index 0000000..a0f118d
--- /dev/null
+++ b/WebCore/storage/SQLException.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SQLException_h
+#define SQLException_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+class SQLException : public ExceptionBase {
+public:
+ static PassRefPtr<SQLException> create(const ExceptionCodeDescription& description)
+ {
+ return adoptRef(new SQLException(description));
+ }
+
+ static const int SQLExceptionOffset = 1000;
+ static const int SQLExceptionMax = 1099;
+
+ enum SQLExceptionCode {
+ UNKNOWN_ERR = SQLExceptionOffset,
+ DATABASE_ERR = SQLExceptionOffset + 1,
+ VERSION_ERR = SQLExceptionOffset + 2,
+ TOO_LARGE_ERR = SQLExceptionOffset + 3,
+ QUOTA_ERR = SQLExceptionOffset + 4,
+ SYNTAX_ERR = SQLExceptionOffset + 5,
+ CONSTRAINT_ERR = SQLExceptionOffset + 6,
+ TIMEOUT_ERR = SQLExceptionOffset + 7
+ };
+
+private:
+ SQLException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // SQLException_h
diff --git a/WebCore/storage/SQLException.idl b/WebCore/storage/SQLException.idl
new file mode 100644
index 0000000..cbbc311
--- /dev/null
+++ b/WebCore/storage/SQLException.idl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=DATABASE,
+ NoStaticTables,
+ DontCheckEnums
+ ] SQLException {
+ readonly attribute unsigned long code;
+ readonly attribute DOMString message;
+
+ // SQLExceptionCode: used only in the sync DB API
+ const unsigned short UNKNOWN_ERR = 0;
+ const unsigned short DATABASE_ERR = 1;
+ const unsigned short VERSION_ERR = 2;
+ const unsigned short TOO_LARGE_ERR = 3;
+ const unsigned short QUOTA_ERR = 4;
+ const unsigned short SYNTAX_ERR = 5;
+ const unsigned short CONSTRAINT_ERR = 6;
+ const unsigned short TIMEOUT_ERR = 7;
+ };
+}
diff --git a/WebCore/storage/SQLResultSet.cpp b/WebCore/storage/SQLResultSet.cpp
index 19c66c7..7482628 100644
--- a/WebCore/storage/SQLResultSet.cpp
+++ b/WebCore/storage/SQLResultSet.cpp
@@ -31,9 +31,6 @@
#if ENABLE(DATABASE)
-#include "ExceptionCode.h"
-#include "SQLValue.h"
-
namespace WebCore {
static unsigned const MaxErrorCode = 2;
diff --git a/WebCore/storage/SQLResultSet.h b/WebCore/storage/SQLResultSet.h
index 5a0ff78..268472f 100644
--- a/WebCore/storage/SQLResultSet.h
+++ b/WebCore/storage/SQLResultSet.h
@@ -31,13 +31,12 @@
#if ENABLE(DATABASE)
+#include "ExceptionCode.h"
#include "SQLResultSetRowList.h"
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
-typedef int ExceptionCode;
-
class SQLResultSet : public ThreadSafeShared<SQLResultSet> {
public:
static PassRefPtr<SQLResultSet> create() { return adoptRef(new SQLResultSet); }
diff --git a/WebCore/storage/SQLResultSet.idl b/WebCore/storage/SQLResultSet.idl
index c98fff6..52f06da 100644
--- a/WebCore/storage/SQLResultSet.idl
+++ b/WebCore/storage/SQLResultSet.idl
@@ -30,12 +30,19 @@ module storage {
interface [
Conditional=DATABASE,
- OmitConstructor
+ OmitConstructor,
+ NoStaticTables
] SQLResultSet {
readonly attribute SQLResultSetRowList rows;
+#if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP
readonly attribute long insertId
getter raises(DOMException);
+#else
+ // Explicitely choose 'long long' here to avoid a 64bit->32bit shortening warning for us.
+ readonly attribute long long insertId
+ getter raises(DOMException);
+#endif
readonly attribute long rowsAffected;
};
}
diff --git a/WebCore/storage/SQLResultSetRowList.idl b/WebCore/storage/SQLResultSetRowList.idl
index 7ae7a9c..26239cb 100644
--- a/WebCore/storage/SQLResultSetRowList.idl
+++ b/WebCore/storage/SQLResultSetRowList.idl
@@ -30,7 +30,8 @@ module storage {
interface [
Conditional=DATABASE,
- OmitConstructor
+ OmitConstructor,
+ NoStaticTables
] SQLResultSetRowList {
readonly attribute unsigned long length;
[Custom] DOMObject item(in unsigned long index);
diff --git a/WebCore/storage/SQLStatement.cpp b/WebCore/storage/SQLStatement.cpp
index b4eb9ef..2d7d78e 100644
--- a/WebCore/storage/SQLStatement.cpp
+++ b/WebCore/storage/SQLStatement.cpp
@@ -31,12 +31,10 @@
#if ENABLE(DATABASE)
#include "Database.h"
-#include "DatabaseAuthorizer.h"
#include "Logging.h"
#include "SQLError.h"
#include "SQLiteDatabase.h"
#include "SQLiteStatement.h"
-#include "SQLResultSet.h"
#include "SQLStatementCallback.h"
#include "SQLStatementErrorCallback.h"
#include "SQLTransaction.h"
@@ -73,14 +71,14 @@ bool SQLStatement::execute(Database* db)
if (m_readOnly)
db->setAuthorizerReadOnly();
- SQLiteDatabase* database = &db->m_sqliteDatabase;
+ SQLiteDatabase* database = &db->sqliteDatabase();
SQLiteStatement statement(*database, m_statement);
int result = statement.prepare();
if (result != SQLResultOk) {
LOG(StorageAPI, "Unable to verify correctness of statement %s - error %i (%s)", m_statement.ascii().data(), result, database->lastErrorMsg());
- m_error = SQLError::create(1, database->lastErrorMsg());
+ m_error = SQLError::create(SQLError::SYNTAX_ERR, database->lastErrorMsg());
return false;
}
@@ -88,7 +86,7 @@ bool SQLStatement::execute(Database* db)
// If this is the case, they might be trying to do something fishy or malicious
if (statement.bindParameterCount() != m_arguments.size()) {
LOG(StorageAPI, "Bind parameter count doesn't match number of question marks");
- m_error = SQLError::create(1, "number of '?'s in statement string does not match argument count");
+ m_error = SQLError::create(SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count");
return false;
}
@@ -101,7 +99,7 @@ bool SQLStatement::execute(Database* db)
if (result != SQLResultOk) {
LOG(StorageAPI, "Failed to bind value index %i to statement for query '%s'", i + 1, m_statement.ascii().data());
- m_error = SQLError::create(1, database->lastErrorMsg());
+ m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg());
return false;
}
}
@@ -125,19 +123,19 @@ bool SQLStatement::execute(Database* db)
} while (result == SQLResultRow);
if (result != SQLResultDone) {
- m_error = SQLError::create(1, database->lastErrorMsg());
+ m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg());
return false;
}
} else if (result == SQLResultDone) {
// Didn't find anything, or was an insert
- if (db->m_databaseAuthorizer->lastActionWasInsert())
+ if (db->lastActionWasInsert())
resultSet->setInsertId(database->lastInsertRowID());
} else if (result == SQLResultFull) {
// Return the Quota error - the delegate will be asked for more space and this statement might be re-run
setFailureDueToQuota();
return false;
} else {
- m_error = SQLError::create(1, database->lastErrorMsg());
+ m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg());
return false;
}
@@ -153,13 +151,13 @@ bool SQLStatement::execute(Database* db)
void SQLStatement::setDatabaseDeletedError()
{
ASSERT(!m_error && !m_resultSet);
- m_error = SQLError::create(0, "unable to execute statement, because the user deleted the database");
+ m_error = SQLError::create(SQLError::UNKNOWN_ERR, "unable to execute statement, because the user deleted the database");
}
void SQLStatement::setVersionMismatchedError()
{
ASSERT(!m_error && !m_resultSet);
- m_error = SQLError::create(2, "current version of the database and `oldVersion` argument do not match");
+ m_error = SQLError::create(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match");
}
bool SQLStatement::performCallback(SQLTransaction* transaction)
@@ -172,9 +170,9 @@ bool SQLStatement::performCallback(SQLTransaction* transaction)
// because then we need to jump to the transaction error callback.
if (m_error) {
ASSERT(m_statementErrorCallback);
- callbackError = m_statementErrorCallback->handleEvent(transaction, m_error.get());
+ callbackError = m_statementErrorCallback->handleEvent(transaction->database()->scriptExecutionContext(), transaction, m_error.get());
} else if (m_statementCallback)
- m_statementCallback->handleEvent(transaction, m_resultSet.get(), callbackError);
+ callbackError = !m_statementCallback->handleEvent(transaction->database()->scriptExecutionContext(), transaction, m_resultSet.get());
// Now release our callbacks, to break reference cycles.
m_statementCallback = 0;
@@ -186,7 +184,7 @@ bool SQLStatement::performCallback(SQLTransaction* transaction)
void SQLStatement::setFailureDueToQuota()
{
ASSERT(!m_error && !m_resultSet);
- m_error = SQLError::create(4, "there was not enough remaining storage space, or the storage quota was reached and the user declined to allow more space");
+ m_error = SQLError::create(SQLError::QUOTA_ERR, "there was not enough remaining storage space, or the storage quota was reached and the user declined to allow more space");
}
void SQLStatement::clearFailureDueToQuota()
@@ -197,7 +195,7 @@ void SQLStatement::clearFailureDueToQuota()
bool SQLStatement::lastExecutionFailedDueToQuota() const
{
- return m_error && m_error->code() == 4;
+ return m_error && m_error->code() == SQLError::QUOTA_ERR;
}
} // namespace WebCore
diff --git a/WebCore/storage/SQLStatement.h b/WebCore/storage/SQLStatement.h
index f01f7bf..89af377 100644
--- a/WebCore/storage/SQLStatement.h
+++ b/WebCore/storage/SQLStatement.h
@@ -31,23 +31,18 @@
#if ENABLE(DATABASE)
#include "PlatformString.h"
-
-#include "SQLError.h"
#include "SQLResultSet.h"
-#include "SQLStatementCallback.h"
-#include "SQLStatementErrorCallback.h"
#include "SQLValue.h"
-
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Threading.h>
+#include <wtf/Forward.h>
#include <wtf/Vector.h>
namespace WebCore {
class Database;
+class SQLError;
+class SQLStatementCallback;
+class SQLStatementErrorCallback;
class SQLTransaction;
-class String;
class SQLStatement : public ThreadSafeShared<SQLStatement> {
public:
@@ -66,7 +61,7 @@ public:
SQLError* sqlError() const { return m_error.get(); }
private:
- SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, bool readOnly);
+ SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, bool readOnly);
void setFailureDueToQuota();
void clearFailureDueToQuota();
diff --git a/WebCore/storage/SQLStatementCallback.h b/WebCore/storage/SQLStatementCallback.h
index 31f5c0c..4bb2e06 100644
--- a/WebCore/storage/SQLStatementCallback.h
+++ b/WebCore/storage/SQLStatementCallback.h
@@ -30,17 +30,18 @@
#if ENABLE(DATABASE)
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
+class ScriptExecutionContext;
class SQLTransaction;
class SQLResultSet;
class SQLStatementCallback : public ThreadSafeShared<SQLStatementCallback> {
public:
virtual ~SQLStatementCallback() { }
- virtual void handleEvent(SQLTransaction*, SQLResultSet*, bool& raisedException) = 0;
+ virtual bool handleEvent(ScriptExecutionContext*, SQLTransaction*, SQLResultSet*) = 0;
};
}
diff --git a/WebCore/storage/SQLStatementCallback.idl b/WebCore/storage/SQLStatementCallback.idl
new file mode 100644
index 0000000..cc25711
--- /dev/null
+++ b/WebCore/storage/SQLStatementCallback.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] SQLStatementCallback {
+ boolean handleEvent(in SQLTransaction transaction, in SQLResultSet resultSet);
+ };
+}
diff --git a/WebCore/storage/SQLStatementErrorCallback.h b/WebCore/storage/SQLStatementErrorCallback.h
index 29127ce..7c45afd 100644
--- a/WebCore/storage/SQLStatementErrorCallback.h
+++ b/WebCore/storage/SQLStatementErrorCallback.h
@@ -31,17 +31,18 @@
#if ENABLE(DATABASE)
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
+class ScriptExecutionContext;
class SQLTransaction;
class SQLError;
class SQLStatementErrorCallback : public ThreadSafeShared<SQLStatementErrorCallback> {
public:
virtual ~SQLStatementErrorCallback() { }
- virtual bool handleEvent(SQLTransaction*, SQLError*) = 0;
+ virtual bool handleEvent(ScriptExecutionContext*, SQLTransaction*, SQLError*) = 0;
};
}
diff --git a/WebCore/storage/SQLStatementErrorCallback.idl b/WebCore/storage/SQLStatementErrorCallback.idl
new file mode 100644
index 0000000..315500d
--- /dev/null
+++ b/WebCore/storage/SQLStatementErrorCallback.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] SQLStatementErrorCallback {
+ [Custom] boolean handleEvent(in SQLTransaction transaction, in SQLError error);
+ };
+}
diff --git a/WebCore/storage/SQLStatementSync.cpp b/WebCore/storage/SQLStatementSync.cpp
new file mode 100644
index 0000000..7be3f50
--- /dev/null
+++ b/WebCore/storage/SQLStatementSync.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SQLStatementSync.h"
+
+#if ENABLE(DATABASE)
+
+#include "DatabaseSync.h"
+#include "SQLException.h"
+#include "SQLResultSet.h"
+#include "SQLValue.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+SQLStatementSync::SQLStatementSync(const String& statement, const Vector<SQLValue>& arguments, bool readOnly)
+ : m_statement(statement)
+ , m_arguments(arguments)
+ , m_readOnly(readOnly)
+{
+ ASSERT(!m_statement.isEmpty());
+}
+
+PassRefPtr<SQLResultSet> SQLStatementSync::execute(DatabaseSync* db, ExceptionCode& ec)
+{
+ if (m_readOnly)
+ db->setAuthorizerReadOnly();
+
+ SQLiteDatabase* database = &db->sqliteDatabase();
+
+ SQLiteStatement statement(*database, m_statement);
+ int result = statement.prepare();
+ if (result != SQLResultOk) {
+ ec = SQLException::SYNTAX_ERR;
+ return 0;
+ }
+
+ if (statement.bindParameterCount() != m_arguments.size()) {
+ ec = SQLException::SYNTAX_ERR;
+ return 0;
+ }
+
+ for (unsigned i = 0; i < m_arguments.size(); ++i) {
+ result = statement.bindValue(i + 1, m_arguments[i]);
+ if (result == SQLResultFull) {
+ ec = SQLException::QUOTA_ERR;
+ return 0;
+ }
+
+ if (result != SQLResultOk) {
+ ec = SQLException::DATABASE_ERR;
+ return 0;
+ }
+ }
+
+ RefPtr<SQLResultSet> resultSet = SQLResultSet::create();
+
+ // Step so we can fetch the column names.
+ result = statement.step();
+ if (result == SQLResultRow) {
+ int columnCount = statement.columnCount();
+ SQLResultSetRowList* rows = resultSet->rows();
+
+ for (int i = 0; i < columnCount; i++)
+ rows->addColumn(statement.getColumnName(i));
+
+ do {
+ for (int i = 0; i < columnCount; i++)
+ rows->addResult(statement.getColumnValue(i));
+
+ result = statement.step();
+ } while (result == SQLResultRow);
+
+ if (result != SQLResultDone) {
+ ec = SQLException::DATABASE_ERR;
+ return 0;
+ }
+ } else if (result == SQLResultDone) {
+ // Didn't find anything, or was an insert.
+ if (db->lastActionWasInsert())
+ resultSet->setInsertId(database->lastInsertRowID());
+ } else if (result == SQLResultFull) {
+ // Quota error, the delegate will be asked for more space and this statement might be re-run.
+ ec = SQLException::QUOTA_ERR;
+ return 0;
+ } else {
+ ec = SQLException::DATABASE_ERR;
+ return 0;
+ }
+
+ resultSet->setRowsAffected(database->lastChanges());
+ return resultSet.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/SQLStatementSync.h b/WebCore/storage/SQLStatementSync.h
new file mode 100644
index 0000000..dc0394c
--- /dev/null
+++ b/WebCore/storage/SQLStatementSync.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SQLStatementSync_h
+#define SQLStatementSync_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include "SQLValue.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class DatabaseSync;
+class SQLResultSet;
+
+class SQLStatementSync {
+public:
+ SQLStatementSync(const String& statement, const Vector<SQLValue>& arguments, bool readOnly);
+
+ PassRefPtr<SQLResultSet> execute(DatabaseSync*, ExceptionCode&);
+
+private:
+ String m_statement;
+ Vector<SQLValue> m_arguments;
+ bool m_readOnly;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // SQLStatementSync_h
diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp
index 754cebc..e43d844 100644
--- a/WebCore/storage/SQLTransaction.cpp
+++ b/WebCore/storage/SQLTransaction.cpp
@@ -31,26 +31,25 @@
#if ENABLE(DATABASE)
-#include "ChromeClient.h"
#include "Database.h"
-#include "DatabaseAuthorizer.h"
-#include "DatabaseDetails.h"
#include "DatabaseThread.h"
-#include "ExceptionCode.h"
#include "Logging.h"
-#include "Page.h"
#include "PlatformString.h"
#include "ScriptExecutionContext.h"
-#include "Settings.h"
#include "SQLError.h"
#include "SQLiteTransaction.h"
-#include "SQLResultSet.h"
#include "SQLStatement.h"
#include "SQLStatementCallback.h"
#include "SQLStatementErrorCallback.h"
+#include "SQLTransactionCallback.h"
#include "SQLTransactionClient.h"
#include "SQLTransactionCoordinator.h"
+#include "SQLTransactionErrorCallback.h"
#include "SQLValue.h"
+#include "VoidCallback.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
// There's no way of knowing exactly how much more space will be required when a statement hits the quota limit.
// For now, we'll arbitrarily choose currentQuota + 1mb.
@@ -65,8 +64,8 @@ PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTr
return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper, readOnly));
}
-SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback,
- PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
+SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
: m_nextStep(&SQLTransaction::acquireLock)
, m_executeSqlAllowed(false)
, m_database(db)
@@ -89,7 +88,7 @@ SQLTransaction::~SQLTransaction()
void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)
{
- if (!m_executeSqlAllowed || m_database->stopped()) {
+ if (!m_executeSqlAllowed || !m_database->opened()) {
e = INVALID_STATE_ERR;
return;
}
@@ -149,7 +148,7 @@ const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod
void SQLTransaction::checkAndHandleClosedDatabase()
{
- if (!m_database->stopped())
+ if (m_database->opened())
return;
// If the database was stopped, don't do anything and cancel queued work
@@ -158,6 +157,10 @@ void SQLTransaction::checkAndHandleClosedDatabase()
m_statementQueue.clear();
m_nextStep = 0;
+ // The next steps should be executed only if we're on the DB thread.
+ if (currentThread() != database()->scriptExecutionContext()->databaseThread()->getThreadID())
+ return;
+
// The current SQLite transaction should be stopped, as well
if (m_sqliteTransaction) {
m_sqliteTransaction->stop();
@@ -230,45 +233,46 @@ void SQLTransaction::lockAcquired()
void SQLTransaction::openTransactionAndPreflight()
{
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
ASSERT(m_lockAcquired);
LOG(StorageAPI, "Opening and preflighting transaction %p", this);
// If the database was deleted, jump to the error callback
if (m_database->deleted()) {
- m_transactionError = SQLError::create(0, "unable to open a transaction, because the user deleted the database");
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database");
handleTransactionError(false);
return;
}
// Set the maximum usage for this transaction if this transactions is not read-only
if (!m_readOnly)
- m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize());
+ m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
ASSERT(!m_sqliteTransaction);
- m_sqliteTransaction.set(new SQLiteTransaction(m_database->m_sqliteDatabase, m_readOnly));
+ m_sqliteTransaction.set(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly));
- m_database->m_databaseAuthorizer->disable();
+ m_database->resetDeletes();
+ m_database->disableAuthorizer();
m_sqliteTransaction->begin();
- m_database->m_databaseAuthorizer->enable();
+ m_database->enableAuthorizer();
// Transaction Steps 1+2 - Open a transaction to the database, jumping to the error callback if that fails
if (!m_sqliteTransaction->inProgress()) {
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
m_sqliteTransaction.clear();
- m_transactionError = SQLError::create(0, "unable to open a transaction to the database");
+ m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to open a transaction to the database");
handleTransactionError(false);
return;
}
// Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail
if (m_wrapper && !m_wrapper->performPreflight(this)) {
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
m_sqliteTransaction.clear();
m_transactionError = m_wrapper->sqlError();
if (!m_transactionError)
- m_transactionError = SQLError::create(0, "unknown error occured setting up transaction");
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction");
handleTransactionError(false);
return;
@@ -286,14 +290,13 @@ void SQLTransaction::deliverTransactionCallback()
if (m_callback) {
m_executeSqlAllowed = true;
- m_callback->handleEvent(this, shouldDeliverErrorCallback);
+ shouldDeliverErrorCallback = !m_callback->handleEvent(m_database->scriptExecutionContext(), this);
m_executeSqlAllowed = false;
- } else
- shouldDeliverErrorCallback = true;
+ }
// Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback
if (shouldDeliverErrorCallback) {
- m_transactionError = SQLError::create(0, "the SQLTransactionCallback was null or threw an exception");
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception");
deliverTransactionErrorCallback();
} else
scheduleToRunStatements();
@@ -322,7 +325,7 @@ void SQLTransaction::runStatements()
// m_shouldRetryCurrentStatement is set to true only when a statement exceeds
// the quota, which can happen only in a read-write transaction. Therefore, there
// is no need to check here if the transaction is read-write.
- m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize());
+ m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
} else {
// If the current statement has already been run, failed due to quota constraints, and we're not retrying it,
// that means it ended in an error. Handle it now
@@ -349,8 +352,7 @@ void SQLTransaction::getNextStatement()
MutexLocker locker(m_statementMutex);
if (!m_statementQueue.isEmpty()) {
- m_currentStatement = m_statementQueue.first();
- m_statementQueue.removeFirst();
+ m_currentStatement = m_statementQueue.takeFirst();
}
}
@@ -359,14 +361,14 @@ bool SQLTransaction::runCurrentStatement()
if (!m_currentStatement)
return false;
- m_database->m_databaseAuthorizer->reset();
+ m_database->resetAuthorizer();
if (m_currentStatement->execute(m_database.get())) {
- if (m_database->m_databaseAuthorizer->lastActionChangedDatabase()) {
+ if (m_database->lastActionChangedDatabase()) {
// Flag this transaction as having changed the database for later delegate notification
m_modifiedDatabase = true;
// Also dirty the size of this database file for calculating quota usage
- m_database->transactionClient()->didExecuteStatement(this);
+ m_database->transactionClient()->didExecuteStatement(database());
}
if (m_currentStatement->hasStatementCallback()) {
@@ -401,7 +403,7 @@ void SQLTransaction::handleCurrentStatementError()
} else {
m_transactionError = m_currentStatement->sqlError();
if (!m_transactionError)
- m_transactionError = SQLError::create(1, "the statement failed to execute");
+ m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute");
handleTransactionError(false);
}
}
@@ -417,7 +419,7 @@ void SQLTransaction::deliverStatementCallback()
m_executeSqlAllowed = false;
if (result) {
- m_transactionError = SQLError::create(0, "the statement callback raised an exception or statement error callback did not return false");
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false");
handleTransactionError(true);
} else
scheduleToRunStatements();
@@ -428,7 +430,7 @@ void SQLTransaction::deliverQuotaIncreaseCallback()
ASSERT(m_currentStatement);
ASSERT(!m_shouldRetryCurrentStatement);
- m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(this);
+ m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database());
m_nextStep = &SQLTransaction::runStatements;
LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
@@ -443,7 +445,7 @@ void SQLTransaction::postflightAndCommit()
if (m_wrapper && !m_wrapper->performPostflight(this)) {
m_transactionError = m_wrapper->sqlError();
if (!m_transactionError)
- m_transactionError = SQLError::create(0, "unknown error occured setting up transaction");
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction");
handleTransactionError(false);
return;
}
@@ -451,20 +453,24 @@ void SQLTransaction::postflightAndCommit()
// Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails
ASSERT(m_sqliteTransaction);
- m_database->m_databaseAuthorizer->disable();
+ m_database->disableAuthorizer();
m_sqliteTransaction->commit();
- m_database->m_databaseAuthorizer->enable();
+ m_database->enableAuthorizer();
// If the commit failed, the transaction will still be marked as "in progress"
if (m_sqliteTransaction->inProgress()) {
- m_transactionError = SQLError::create(0, "failed to commit the transaction");
+ m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction");
handleTransactionError(false);
return;
}
- // The commit was successful, notify the delegates if the transaction modified this database
+ // Vacuum the database if anything was deleted.
+ if (m_database->hadDeletes())
+ m_database->incrementalVacuumIfNeeded();
+
+ // The commit was successful. If the transaction modified this database, notify the delegates.
if (m_modifiedDatabase)
- m_database->transactionClient()->didCommitTransaction(this);
+ m_database->transactionClient()->didCommitWriteTransaction(database());
// Now release our unneeded callbacks, to break reference cycles.
m_callback = 0;
@@ -502,7 +508,7 @@ void SQLTransaction::cleanupAfterSuccessCallback()
// Transaction Step 11 - End transaction steps
// There is no next step
LOG(StorageAPI, "Transaction %p is complete\n", this);
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
m_sqliteTransaction.clear();
m_nextStep = 0;
@@ -541,7 +547,7 @@ void SQLTransaction::deliverTransactionErrorCallback()
// Transaction Step 12 - If exists, invoke error callback with the last
// error to have occurred in this transaction.
if (m_errorCallback)
- m_errorCallback->handleEvent(m_transactionError.get());
+ m_errorCallback->handleEvent(m_database->scriptExecutionContext(), m_transactionError.get());
m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
@@ -552,15 +558,15 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback()
{
ASSERT(m_lockAcquired);
- m_database->m_databaseAuthorizer->disable();
+ m_database->disableAuthorizer();
if (m_sqliteTransaction) {
// Transaction Step 12 - Rollback the transaction.
m_sqliteTransaction->rollback();
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
m_sqliteTransaction.clear();
}
- m_database->m_databaseAuthorizer->enable();
+ m_database->enableAuthorizer();
// Transaction Step 12 - Any still-pending statements in the transaction are discarded.
{
@@ -570,7 +576,7 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback()
// Transaction is complete! There is no next step
LOG(StorageAPI, "Transaction %p is complete with an error\n", this);
- ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
m_nextStep = 0;
// Now release our callbacks, to break reference cycles.
diff --git a/WebCore/storage/SQLTransaction.h b/WebCore/storage/SQLTransaction.h
index 1b02d01..5c62ca2 100644
--- a/WebCore/storage/SQLTransaction.h
+++ b/WebCore/storage/SQLTransaction.h
@@ -30,27 +30,23 @@
#if ENABLE(DATABASE)
-#include <wtf/Threading.h>
-
-#include "SQLiteTransaction.h"
+#include "ExceptionCode.h"
#include "SQLStatement.h"
-#include "SQLTransactionCallback.h"
-#include "SQLTransactionErrorCallback.h"
#include <wtf/Deque.h>
#include <wtf/Forward.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/RefPtr.h>
+#include <wtf/ThreadSafeShared.h>
#include <wtf/Vector.h>
namespace WebCore {
-typedef int ExceptionCode;
-
class Database;
class SQLError;
+class SQLiteTransaction;
class SQLStatementCallback;
class SQLStatementErrorCallback;
class SQLTransaction;
+class SQLTransactionCallback;
+class SQLTransactionErrorCallback;
class SQLValue;
class String;
class VoidCallback;
@@ -72,7 +68,7 @@ public:
~SQLTransaction();
void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments,
- PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e);
+ PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, ExceptionCode&);
void lockAcquired();
bool performNextStep();
diff --git a/WebCore/storage/SQLTransaction.idl b/WebCore/storage/SQLTransaction.idl
index 7d694e8..4e353d3 100644
--- a/WebCore/storage/SQLTransaction.idl
+++ b/WebCore/storage/SQLTransaction.idl
@@ -30,7 +30,8 @@ module storage {
interface [
Conditional=DATABASE,
- OmitConstructor
+ OmitConstructor,
+ NoStaticTables
] SQLTransaction {
[Custom] void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback, in SQLStatementErrorCallback errorCallback);
};
diff --git a/WebCore/storage/SQLTransactionCallback.h b/WebCore/storage/SQLTransactionCallback.h
index de3e85dc..73123ee 100644
--- a/WebCore/storage/SQLTransactionCallback.h
+++ b/WebCore/storage/SQLTransactionCallback.h
@@ -31,17 +31,17 @@
#if ENABLE(DATABASE)
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
+class ScriptExecutionContext;
class SQLTransaction;
-class SQLError;
class SQLTransactionCallback : public ThreadSafeShared<SQLTransactionCallback> {
public:
virtual ~SQLTransactionCallback() { }
- virtual void handleEvent(SQLTransaction*, bool& raisedException) = 0;
+ virtual bool handleEvent(ScriptExecutionContext*, SQLTransaction*) = 0;
};
}
diff --git a/WebCore/storage/SQLTransactionCallback.idl b/WebCore/storage/SQLTransactionCallback.idl
new file mode 100644
index 0000000..d1bc77c
--- /dev/null
+++ b/WebCore/storage/SQLTransactionCallback.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] SQLTransactionCallback {
+ boolean handleEvent(in SQLTransaction transaction);
+ };
+}
diff --git a/WebCore/storage/SQLTransactionClient.cpp b/WebCore/storage/SQLTransactionClient.cpp
index 6064c99..6b95606 100644
--- a/WebCore/storage/SQLTransactionClient.cpp
+++ b/WebCore/storage/SQLTransactionClient.cpp
@@ -33,39 +33,27 @@
#if ENABLE(DATABASE)
-#include "Chrome.h"
-#include "ChromeClient.h"
-#include "Database.h"
-#include "DatabaseThread.h"
+#include "AbstractDatabase.h"
#include "DatabaseTracker.h"
-#include "Document.h"
-#include "OriginQuotaManager.h"
-#include "Page.h"
-#include "SQLTransaction.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
namespace WebCore {
-void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
+void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database)
{
- ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
- Database* database = transaction->database();
DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
database->securityOrigin(), database->stringIdentifier());
}
-void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
+void SQLTransactionClient::didExecuteStatement(AbstractDatabase* database)
{
- ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
- OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
- Locker<OriginQuotaManager> locker(manager);
- manager.markDatabase(transaction->database());
+ DatabaseTracker::tracker().databaseChanged(database);
}
-bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
+bool SQLTransactionClient::didExceedQuota(AbstractDatabase* database)
{
- ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
- Database* database = transaction->database();
-
+ ASSERT(database->scriptExecutionContext()->isContextThread());
unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
database->scriptExecutionContext()->databaseExceededQuota(database->stringIdentifier());
unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
diff --git a/WebCore/storage/SQLTransactionClient.h b/WebCore/storage/SQLTransactionClient.h
index 801647b..fed0657 100644
--- a/WebCore/storage/SQLTransactionClient.h
+++ b/WebCore/storage/SQLTransactionClient.h
@@ -37,16 +37,17 @@
namespace WebCore {
- class SQLTransaction;
-
- // A client to the SQLTransaction class. Allows SQLTransaction to notify interested
- // parties that certain things have happened in a transaction.
- class SQLTransactionClient : public Noncopyable {
- public:
- void didCommitTransaction(SQLTransaction*);
- void didExecuteStatement(SQLTransaction*);
- bool didExceedQuota(SQLTransaction*);
- };
+class AbstractDatabase;
+
+// A client to the SQLTransaction class. Allows SQLTransaction to notify interested
+// parties that certain things have happened in a transaction.
+class SQLTransactionClient : public Noncopyable {
+public:
+ void didCommitWriteTransaction(AbstractDatabase*);
+ void didExecuteStatement(AbstractDatabase*);
+ bool didExceedQuota(AbstractDatabase*);
+};
+
}
#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/SQLTransactionCoordinator.cpp b/WebCore/storage/SQLTransactionCoordinator.cpp
index 0fe5bda..104ea10 100644
--- a/WebCore/storage/SQLTransactionCoordinator.cpp
+++ b/WebCore/storage/SQLTransactionCoordinator.cpp
@@ -33,7 +33,6 @@
#if ENABLE(DATABASE)
-#include "CString.h"
#include "Database.h"
#include "SQLTransaction.h"
#include <wtf/Deque.h>
@@ -58,8 +57,7 @@ void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& inf
RefPtr<SQLTransaction> firstPendingTransaction = info.pendingTransactions.first();
if (firstPendingTransaction->isReadOnly()) {
do {
- firstPendingTransaction = info.pendingTransactions.first();
- info.pendingTransactions.removeFirst();
+ firstPendingTransaction = info.pendingTransactions.takeFirst();
info.activeReadTransactions.add(firstPendingTransaction);
firstPendingTransaction->lockAcquired();
} while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly());
diff --git a/WebCore/storage/SQLTransactionCoordinator.h b/WebCore/storage/SQLTransactionCoordinator.h
index a51084f..247ad13 100644
--- a/WebCore/storage/SQLTransactionCoordinator.h
+++ b/WebCore/storage/SQLTransactionCoordinator.h
@@ -33,7 +33,6 @@
#if ENABLE(DATABASE)
-#include "CString.h"
#include "StringHash.h"
#include <wtf/Deque.h>
#include <wtf/HashMap.h>
diff --git a/WebCore/storage/SQLTransactionErrorCallback.h b/WebCore/storage/SQLTransactionErrorCallback.h
index de99212..71580eb 100644
--- a/WebCore/storage/SQLTransactionErrorCallback.h
+++ b/WebCore/storage/SQLTransactionErrorCallback.h
@@ -31,17 +31,18 @@
#if ENABLE(DATABASE)
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeShared.h>
namespace WebCore {
- class SQLError;
+class ScriptExecutionContext;
+class SQLError;
- class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> {
- public:
- virtual ~SQLTransactionErrorCallback() { }
- virtual void handleEvent(SQLError*) = 0;
- };
+class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> {
+public:
+ virtual ~SQLTransactionErrorCallback() { }
+ virtual bool handleEvent(ScriptExecutionContext*, SQLError*) = 0;
+};
}
diff --git a/WebCore/storage/SQLTransactionErrorCallback.idl b/WebCore/storage/SQLTransactionErrorCallback.idl
new file mode 100644
index 0000000..779ba69
--- /dev/null
+++ b/WebCore/storage/SQLTransactionErrorCallback.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] SQLTransactionErrorCallback {
+ boolean handleEvent(in SQLError error);
+ };
+}
diff --git a/WebCore/storage/SQLTransactionSync.cpp b/WebCore/storage/SQLTransactionSync.cpp
new file mode 100644
index 0000000..883721c
--- /dev/null
+++ b/WebCore/storage/SQLTransactionSync.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SQLTransactionSync.h"
+
+#if ENABLE(DATABASE)
+
+#include "DatabaseSync.h"
+#include "PlatformString.h"
+#include "SQLException.h"
+#include "SQLResultSet.h"
+#include "SQLStatementSync.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionSyncCallback.h"
+#include "SQLValue.h"
+#include "SQLiteTransaction.h"
+#include "ScriptExecutionContext.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<SQLTransactionSync> SQLTransactionSync::create(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly)
+{
+ return adoptRef(new SQLTransactionSync(db, callback, readOnly));
+}
+
+SQLTransactionSync::SQLTransactionSync(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly)
+ : m_database(db)
+ , m_callback(callback)
+ , m_readOnly(readOnly)
+ , m_modifiedDatabase(false)
+ , m_transactionClient(new SQLTransactionClient())
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+}
+
+SQLTransactionSync::~SQLTransactionSync()
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ if (m_sqliteTransaction && m_sqliteTransaction->inProgress())
+ rollback();
+}
+
+PassRefPtr<SQLResultSet> SQLTransactionSync::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, ExceptionCode& ec)
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ if (!m_database->opened()) {
+ ec = SQLException::UNKNOWN_ERR;
+ return 0;
+ }
+
+ if (!m_database->versionMatchesExpected()) {
+ ec = SQLException::VERSION_ERR;
+ return 0;
+ }
+
+ if (sqlStatement.isEmpty())
+ return 0;
+
+ bool readOnlyMode = m_readOnly || m_database->scriptExecutionContext()->isDatabaseReadOnly();
+ SQLStatementSync statement(sqlStatement, arguments, readOnlyMode);
+
+ m_database->resetAuthorizer();
+ bool retryStatement = true;
+ RefPtr<SQLResultSet> resultSet;
+ while (retryStatement) {
+ retryStatement = false;
+ resultSet = statement.execute(m_database.get(), ec);
+ if (!resultSet) {
+ if (m_sqliteTransaction->wasRolledBackBySqlite())
+ return 0;
+
+ if (ec == SQLException::QUOTA_ERR) {
+ if (m_transactionClient->didExceedQuota(database())) {
+ ec = 0;
+ retryStatement = true;
+ } else
+ return 0;
+ }
+ }
+ }
+
+ if (m_database->lastActionChangedDatabase()) {
+ m_modifiedDatabase = true;
+ m_transactionClient->didExecuteStatement(database());
+ }
+
+ return resultSet.release();
+}
+
+ExceptionCode SQLTransactionSync::begin()
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ if (!m_database->opened())
+ return SQLException::UNKNOWN_ERR;
+
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+
+ // Set the maximum usage for this transaction if this transactions is not read-only.
+ if (!m_readOnly)
+ m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
+
+ ASSERT(!m_sqliteTransaction);
+ m_sqliteTransaction.set(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly));
+
+ m_database->resetDeletes();
+ m_database->disableAuthorizer();
+ m_sqliteTransaction->begin();
+ m_database->enableAuthorizer();
+
+ // Check if begin() succeeded.
+ if (!m_sqliteTransaction->inProgress()) {
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+ m_sqliteTransaction.clear();
+ return SQLException::DATABASE_ERR;
+ }
+
+ return 0;
+}
+
+ExceptionCode SQLTransactionSync::execute()
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ if (!m_database->opened() || (m_callback && !m_callback->handleEvent(m_database->scriptExecutionContext(), this))) {
+ m_callback = 0;
+ return SQLException::UNKNOWN_ERR;
+ }
+
+ m_callback = 0;
+ return 0;
+}
+
+ExceptionCode SQLTransactionSync::commit()
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ if (!m_database->opened())
+ return SQLException::UNKNOWN_ERR;
+
+ ASSERT(m_sqliteTransaction);
+
+ m_database->disableAuthorizer();
+ m_sqliteTransaction->commit();
+ m_database->enableAuthorizer();
+
+ // If the commit failed, the transaction will still be marked as "in progress"
+ if (m_sqliteTransaction->inProgress())
+ return SQLException::DATABASE_ERR;
+
+ m_sqliteTransaction.clear();
+
+ // Vacuum the database if anything was deleted.
+ if (m_database->hadDeletes())
+ m_database->incrementalVacuumIfNeeded();
+
+ // The commit was successful. If the transaction modified this database, notify the delegates.
+ if (m_modifiedDatabase)
+ m_transactionClient->didCommitWriteTransaction(database());
+
+ return 0;
+}
+
+void SQLTransactionSync::rollback()
+{
+ ASSERT(m_database->scriptExecutionContext()->isContextThread());
+ m_database->disableAuthorizer();
+ if (m_sqliteTransaction) {
+ m_sqliteTransaction->rollback();
+ m_sqliteTransaction.clear();
+ }
+ m_database->enableAuthorizer();
+
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/SQLTransactionSync.h b/WebCore/storage/SQLTransactionSync.h
new file mode 100644
index 0000000..025215b
--- /dev/null
+++ b/WebCore/storage/SQLTransactionSync.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SQLTransactionSync_h
+#define SQLTransactionSync_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionCode.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class DatabaseSync;
+class SQLResultSet;
+class SQLTransactionClient;
+class SQLTransactionSyncCallback;
+class SQLValue;
+class SQLiteTransaction;
+class String;
+
+// Instances of this class should be created and used only on the worker's context thread.
+class SQLTransactionSync : public RefCounted<SQLTransactionSync> {
+public:
+ static PassRefPtr<SQLTransactionSync> create(DatabaseSync*, PassRefPtr<SQLTransactionSyncCallback>, bool readOnly = false);
+
+ ~SQLTransactionSync();
+
+ PassRefPtr<SQLResultSet> executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, ExceptionCode&);
+
+ DatabaseSync* database() { return m_database.get(); }
+ bool isReadOnly() const { return m_readOnly; }
+
+ ExceptionCode begin();
+ ExceptionCode execute();
+ ExceptionCode commit();
+ void rollback();
+
+private:
+ SQLTransactionSync(DatabaseSync*, PassRefPtr<SQLTransactionSyncCallback>, bool readOnly);
+
+ RefPtr<DatabaseSync> m_database;
+ RefPtr<SQLTransactionSyncCallback> m_callback;
+ bool m_readOnly;
+
+ bool m_modifiedDatabase;
+ OwnPtr<SQLTransactionClient> m_transactionClient;
+ OwnPtr<SQLiteTransaction> m_sqliteTransaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // SQLTransactionSync_h
diff --git a/WebCore/storage/SQLTransactionSync.idl b/WebCore/storage/SQLTransactionSync.idl
new file mode 100644
index 0000000..003a21d
--- /dev/null
+++ b/WebCore/storage/SQLTransactionSync.idl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+
+ interface [
+ Conditional=DATABASE,
+ OmitConstructor,
+ NoStaticTables
+ ] SQLTransactionSync {
+ [Custom] SQLResultSet executeSql(in DOMString sqlStatement, in ObjectArray arguments);
+ };
+}
diff --git a/WebCore/storage/SQLTransactionSyncCallback.h b/WebCore/storage/SQLTransactionSyncCallback.h
new file mode 100644
index 0000000..557db86
--- /dev/null
+++ b/WebCore/storage/SQLTransactionSyncCallback.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SQLTransactionSyncCallback_h
+#define SQLTransactionSyncCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+class SQLTransactionSync;
+
+// Instances of this class should be created and used only on the worker's context thread.
+class SQLTransactionSyncCallback : public RefCounted<SQLTransactionSyncCallback> {
+public:
+ virtual ~SQLTransactionSyncCallback() { }
+ virtual bool handleEvent(ScriptExecutionContext*, SQLTransactionSync*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLTransactionSyncCallback_h
diff --git a/WebCore/storage/SQLTransactionSyncCallback.idl b/WebCore/storage/SQLTransactionSyncCallback.idl
new file mode 100644
index 0000000..b0fffca
--- /dev/null
+++ b/WebCore/storage/SQLTransactionSyncCallback.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module storage {
+ interface [
+ Conditional=DATABASE,
+ Callback
+ ] SQLTransactionSyncCallback {
+ boolean handleEvent(in SQLTransactionSync transaction);
+ };
+}
diff --git a/WebCore/storage/StorageAreaImpl.cpp b/WebCore/storage/StorageAreaImpl.cpp
index aa04781..dc25e54 100644
--- a/WebCore/storage/StorageAreaImpl.cpp
+++ b/WebCore/storage/StorageAreaImpl.cpp
@@ -44,12 +44,7 @@ StorageAreaImpl::~StorageAreaImpl()
ASSERT(isMainThread());
}
-PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
-{
- return adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota));
-}
-
-StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
+inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
: m_storageType(storageType)
, m_securityOrigin(origin)
, m_storageMap(StorageMap::create(quota))
@@ -61,13 +56,20 @@ StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOri
ASSERT(isMainThread());
ASSERT(m_securityOrigin);
ASSERT(m_storageMap);
+}
+
+PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
+{
+ RefPtr<StorageAreaImpl> area = adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota));
// FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing,
- // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
- if (m_storageSyncManager) {
- m_storageAreaSync = StorageAreaSync::create(m_storageSyncManager, this, m_securityOrigin->databaseIdentifier());
- ASSERT(m_storageAreaSync);
+ // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
+ if (area->m_storageSyncManager) {
+ area->m_storageAreaSync = StorageAreaSync::create(area->m_storageSyncManager, area.get(), area->m_securityOrigin->databaseIdentifier());
+ ASSERT(area->m_storageAreaSync);
}
+
+ return area.release();
}
PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy()
diff --git a/WebCore/storage/StorageAreaSync.cpp b/WebCore/storage/StorageAreaSync.cpp
index d4eba76..f2008ab 100644
--- a/WebCore/storage/StorageAreaSync.cpp
+++ b/WebCore/storage/StorageAreaSync.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,14 +28,16 @@
#if ENABLE(DOM_STORAGE)
-#include "CString.h"
#include "EventNames.h"
+#include "FileSystem.h"
#include "HTMLElement.h"
-#include "SecurityOrigin.h"
+#include "SQLiteFileSystem.h"
#include "SQLiteStatement.h"
+#include "SecurityOrigin.h"
#include "StorageAreaImpl.h"
#include "StorageSyncManager.h"
#include "SuddenTermination.h"
+#include <wtf/text/CString.h>
namespace WebCore {
@@ -43,12 +45,11 @@ namespace WebCore {
// Instead, queue up a batch of items to sync and actually do the sync at the following interval.
static const double StorageSyncInterval = 1.0;
-PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier)
-{
- return adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier));
-}
+// A sane limit on how many items we'll schedule to sync all at once. This makes it
+// much harder to starve the rest of LocalStorage and the OS's IO subsystem in general.
+static const int MaxiumItemsToSync = 100;
-StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier)
+inline StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier)
: m_syncTimer(this, &StorageAreaSync::syncTimerFired)
, m_itemsCleared(false)
, m_finalSyncScheduled(false)
@@ -57,16 +58,25 @@ StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManag
, m_databaseIdentifier(databaseIdentifier.crossThreadString())
, m_clearItemsWhileSyncing(false)
, m_syncScheduled(false)
+ , m_syncInProgress(false)
+ , m_databaseOpenFailed(false)
, m_importComplete(false)
{
ASSERT(isMainThread());
ASSERT(m_storageArea);
ASSERT(m_syncManager);
+}
+
+PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier)
+{
+ RefPtr<StorageAreaSync> area = adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier));
// FIXME: If it can't import, then the default WebKit behavior should be that of private browsing,
- // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
- if (!m_syncManager->scheduleImport(this))
- m_importComplete = true;
+ // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
+ if (!area->m_syncManager->scheduleImport(area.get()))
+ area->m_importComplete = true;
+
+ return area.release();
}
StorageAreaSync::~StorageAreaSync()
@@ -92,8 +102,9 @@ void StorageAreaSync::scheduleFinalSync()
}
// FIXME: This is synchronous. We should do it on the background process, but
// we should do it safely.
- syncTimerFired(&m_syncTimer);
m_finalSyncScheduled = true;
+ syncTimerFired(&m_syncTimer);
+ m_syncManager->scheduleDeleteEmptyDatabase(this);
}
void StorageAreaSync::scheduleItemForSync(const String& key, const String& value)
@@ -131,20 +142,43 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
{
ASSERT(isMainThread());
- HashMap<String, String>::iterator it = m_changedItems.begin();
- HashMap<String, String>::iterator end = m_changedItems.end();
-
+ bool partialSync = false;
{
MutexLocker locker(m_syncLock);
+ // Do not schedule another sync if we're still trying to complete the
+ // previous one. But, if we're shutting down, schedule it anyway.
+ if (m_syncInProgress && !m_finalSyncScheduled) {
+ ASSERT(!m_syncTimer.isActive());
+ m_syncTimer.startOneShot(StorageSyncInterval);
+ return;
+ }
+
if (m_itemsCleared) {
m_itemsPendingSync.clear();
m_clearItemsWhileSyncing = true;
m_itemsCleared = false;
}
- for (; it != end; ++it)
- m_itemsPendingSync.set(it->first.crossThreadString(), it->second.crossThreadString());
+ HashMap<String, String>::iterator changed_it = m_changedItems.begin();
+ HashMap<String, String>::iterator changed_end = m_changedItems.end();
+ for (int count = 0; changed_it != changed_end; ++count, ++changed_it) {
+ if (count >= MaxiumItemsToSync && !m_finalSyncScheduled) {
+ partialSync = true;
+ break;
+ }
+ m_itemsPendingSync.set(changed_it->first.crossThreadString(), changed_it->second.crossThreadString());
+ }
+
+ if (partialSync) {
+ // We can't do the fast path of simply clearing all items, so we'll need to manually
+ // remove them one by one. Done under lock since m_itemsPendingSync is modified by
+ // the background thread.
+ HashMap<String, String>::iterator pending_it = m_itemsPendingSync.begin();
+ HashMap<String, String>::iterator pending_end = m_itemsPendingSync.end();
+ for (; pending_it != pending_end; ++pending_it)
+ m_changedItems.remove(pending_it->first);
+ }
if (!m_syncScheduled) {
m_syncScheduled = true;
@@ -157,35 +191,60 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
}
}
- // The following is balanced by the calls to disableSuddenTermination in the
- // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions.
- enableSuddenTermination();
+ if (partialSync) {
+ // If we didn't finish syncing, then we need to finish the job later.
+ ASSERT(!m_syncTimer.isActive());
+ m_syncTimer.startOneShot(StorageSyncInterval);
+ } else {
+ // The following is balanced by the calls to disableSuddenTermination in the
+ // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions.
+ enableSuddenTermination();
- m_changedItems.clear();
+ m_changedItems.clear();
+ }
}
-void StorageAreaSync::performImport()
+void StorageAreaSync::openDatabase(OpenDatabaseParamType openingStrategy)
{
ASSERT(!isMainThread());
ASSERT(!m_database.isOpen());
+ ASSERT(!m_databaseOpenFailed);
String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
+ if (!fileExists(databaseFilename) && openingStrategy == SkipIfNonExistent)
+ return;
+
if (databaseFilename.isEmpty()) {
LOG_ERROR("Filename for local storage database is empty - cannot open for persistent storage");
markImported();
+ m_databaseOpenFailed = true;
return;
}
if (!m_database.open(databaseFilename)) {
LOG_ERROR("Failed to open database file %s for local storage", databaseFilename.utf8().data());
markImported();
+ m_databaseOpenFailed = true;
return;
}
if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL)")) {
LOG_ERROR("Failed to create table ItemTable for local storage");
markImported();
+ m_databaseOpenFailed = true;
+ return;
+ }
+}
+
+void StorageAreaSync::performImport()
+{
+ ASSERT(!isMainThread());
+ ASSERT(!m_database.isOpen());
+
+ openDatabase(SkipIfNonExistent);
+ if (!m_database.isOpen()) {
+ markImported();
return;
}
@@ -251,6 +310,12 @@ void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items
{
ASSERT(!isMainThread());
+ if (items.isEmpty() && !clearItems)
+ return;
+ if (m_databaseOpenFailed)
+ return;
+ if (!m_database.isOpen())
+ openDatabase(CreateIfNonExistent);
if (!m_database.isOpen())
return;
@@ -319,15 +384,49 @@ void StorageAreaSync::performSync()
m_clearItemsWhileSyncing = false;
m_syncScheduled = false;
+ m_syncInProgress = true;
}
sync(clearItems, items);
+ {
+ MutexLocker locker(m_syncLock);
+ m_syncInProgress = false;
+ }
+
// The following is balanced by the call to disableSuddenTermination in the
// syncTimerFired function.
enableSuddenTermination();
}
+void StorageAreaSync::deleteEmptyDatabase()
+{
+ ASSERT(!isMainThread());
+ if (!m_database.isOpen())
+ return;
+
+ SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable");
+ if (query.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to count number of rows in ItemTable for local storage");
+ return;
+ }
+
+ int result = query.step();
+ if (result != SQLResultRow) {
+ LOG_ERROR("No results when counting number of rows in ItemTable for local storage");
+ return;
+ }
+
+ int count = query.getColumnInt(0);
+ if (!count) {
+ query.finalize();
+ m_database.close();
+ String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
+ if (!SQLiteFileSystem::deleteDatabaseFile(databaseFilename))
+ LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data());
+ }
+}
+
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
diff --git a/WebCore/storage/StorageAreaSync.h b/WebCore/storage/StorageAreaSync.h
index 9afdfde..94c4670 100644
--- a/WebCore/storage/StorageAreaSync.h
+++ b/WebCore/storage/StorageAreaSync.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,6 @@
#if ENABLE(DOM_STORAGE)
-#include "PlatformString.h"
#include "SQLiteDatabase.h"
#include "StringHash.h"
#include "Timer.h"
@@ -42,7 +41,7 @@ namespace WebCore {
class StorageAreaSync : public RefCounted<StorageAreaSync> {
public:
- static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier);
+ static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier);
~StorageAreaSync();
void scheduleFinalSync();
@@ -52,7 +51,7 @@ namespace WebCore {
void scheduleClear();
private:
- StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier);
+ StorageAreaSync(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier);
void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame);
@@ -73,9 +72,16 @@ namespace WebCore {
// Called from the background thread
void performImport();
void performSync();
+ void deleteEmptyDatabase();
private:
+ enum OpenDatabaseParamType {
+ CreateIfNonExistent,
+ SkipIfNonExistent
+ };
+
void syncTimerFired(Timer<StorageAreaSync>*);
+ void openDatabase(OpenDatabaseParamType openingStrategy);
void sync(bool clearItems, const HashMap<String, String>& items);
const String m_databaseIdentifier;
@@ -84,6 +90,8 @@ namespace WebCore {
HashMap<String, String> m_itemsPendingSync;
bool m_clearItemsWhileSyncing;
bool m_syncScheduled;
+ bool m_syncInProgress;
+ bool m_databaseOpenFailed;
mutable Mutex m_importLock;
mutable ThreadCondition m_importCondition;
diff --git a/WebCore/storage/StorageEvent.cpp b/WebCore/storage/StorageEvent.cpp
index 126aca0..a08cde2 100644
--- a/WebCore/storage/StorageEvent.cpp
+++ b/WebCore/storage/StorageEvent.cpp
@@ -41,22 +41,26 @@ StorageEvent::StorageEvent()
{
}
-PassRefPtr<StorageEvent> StorageEvent::create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea)
+StorageEvent::~StorageEvent()
{
- return adoptRef(new StorageEvent(type, key, oldValue, newValue, uri, storageArea));
}
-StorageEvent::StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea)
+PassRefPtr<StorageEvent> StorageEvent::create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea)
+{
+ return adoptRef(new StorageEvent(type, key, oldValue, newValue, url, storageArea));
+}
+
+StorageEvent::StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea)
: Event(type, false, false)
, m_key(key)
, m_oldValue(oldValue)
, m_newValue(newValue)
- , m_uri(uri)
+ , m_url(url)
, m_storageArea(storageArea)
{
}
-void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea)
+void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea)
{
if (dispatched())
return;
@@ -66,7 +70,7 @@ void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bo
m_key = key;
m_oldValue = oldValue;
m_newValue = newValue;
- m_uri = uri;
+ m_url = url;
m_storageArea = storageArea;
}
diff --git a/WebCore/storage/StorageEvent.h b/WebCore/storage/StorageEvent.h
index fa7535b..8e558a8 100644
--- a/WebCore/storage/StorageEvent.h
+++ b/WebCore/storage/StorageEvent.h
@@ -38,29 +38,30 @@ namespace WebCore {
class StorageEvent : public Event {
public:
static PassRefPtr<StorageEvent> create();
- static PassRefPtr<StorageEvent> create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea);
+ static PassRefPtr<StorageEvent> create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea);
+ virtual ~StorageEvent();
const String& key() const { return m_key; }
const String& oldValue() const { return m_oldValue; }
const String& newValue() const { return m_newValue; }
- const String& uri() const { return m_uri; }
+ const String& url() const { return m_url; }
Storage* storageArea() const { return m_storageArea.get(); }
- void initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea);
+ void initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea);
// Needed once we support init<blank>EventNS
- // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString uriArg, Storage storageAreaArg);
+ // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, Storage storageAreaArg);
virtual bool isStorageEvent() const { return true; }
private:
StorageEvent();
- StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea);
+ StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea);
String m_key;
String m_oldValue;
String m_newValue;
- String m_uri;
+ String m_url;
RefPtr<Storage> m_storageArea;
};
diff --git a/WebCore/storage/StorageEvent.idl b/WebCore/storage/StorageEvent.idl
index 3e77eda..3464caa 100644
--- a/WebCore/storage/StorageEvent.idl
+++ b/WebCore/storage/StorageEvent.idl
@@ -31,12 +31,12 @@ module storage {
readonly attribute [ConvertNullStringTo=Null] DOMString key;
readonly attribute [ConvertNullStringTo=Null] DOMString oldValue;
readonly attribute [ConvertNullStringTo=Null] DOMString newValue;
- readonly attribute DOMString uri;
+ readonly attribute DOMString url;
readonly attribute Storage storageArea;
- void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in [ConvertNullToNullString] DOMString oldValueArg, in [ConvertNullToNullString] DOMString newValueArg, in DOMString uriArg, in Storage storageAreaArg);
+ void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in [ConvertNullToNullString] DOMString oldValueArg, in [ConvertNullToNullString] DOMString newValueArg, in DOMString urlArg, in Storage storageAreaArg);
// Needed once we support init<blank>EventNS
- // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString uriArg, in Storage storageAreaArg);
+ // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, in Storage storageAreaArg);
};
}
diff --git a/WebCore/storage/StorageEventDispatcher.cpp b/WebCore/storage/StorageEventDispatcher.cpp
index dc0295b..5833c59 100644
--- a/WebCore/storage/StorageEventDispatcher.cpp
+++ b/WebCore/storage/StorageEventDispatcher.cpp
@@ -54,8 +54,12 @@ void StorageEventDispatcher::dispatch(const String& key, const String& oldValue,
frames.append(frame);
}
- for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->enqueueStorageEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->sessionStorage()));
+ for (unsigned i = 0; i < frames.size(); ++i) {
+ ExceptionCode ec = 0;
+ Storage* storage = frames[i]->domWindow()->sessionStorage(ec);
+ if (!ec)
+ frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
+ }
} else {
// Send events to every page.
const HashSet<Page*>& pages = page->group().pages();
@@ -67,8 +71,12 @@ void StorageEventDispatcher::dispatch(const String& key, const String& oldValue,
}
}
- for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->enqueueStorageEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->localStorage()));
+ for (unsigned i = 0; i < frames.size(); ++i) {
+ ExceptionCode ec = 0;
+ Storage* storage = frames[i]->domWindow()->localStorage(ec);
+ if (!ec)
+ frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
+ }
}
}
diff --git a/WebCore/storage/StorageNamespace.cpp b/WebCore/storage/StorageNamespace.cpp
index b54ba16..ce36608 100644
--- a/WebCore/storage/StorageNamespace.cpp
+++ b/WebCore/storage/StorageNamespace.cpp
@@ -42,9 +42,9 @@ PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const Strin
}
// The page argument is only used by the Chromium port.
-PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*)
+PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*, unsigned quota)
{
- return StorageNamespaceImpl::sessionStorageNamespace();
+ return StorageNamespaceImpl::sessionStorageNamespace(quota);
}
} // namespace WebCore
diff --git a/WebCore/storage/StorageNamespace.h b/WebCore/storage/StorageNamespace.h
index e84e5a6..8f09b1a 100644
--- a/WebCore/storage/StorageNamespace.h
+++ b/WebCore/storage/StorageNamespace.h
@@ -43,7 +43,7 @@ class StorageArea;
class StorageNamespace : public RefCounted<StorageNamespace> {
public:
static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
- static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*);
+ static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*, unsigned quota);
virtual ~StorageNamespace() { }
virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0;
diff --git a/WebCore/storage/StorageNamespaceImpl.cpp b/WebCore/storage/StorageNamespaceImpl.cpp
index 19ff6b4..557dd76 100644
--- a/WebCore/storage/StorageNamespaceImpl.cpp
+++ b/WebCore/storage/StorageNamespaceImpl.cpp
@@ -58,9 +58,9 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const S
return it->second;
}
-PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace()
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(unsigned quota)
{
- return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), StorageMap::noQuota));
+ return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), quota));
}
StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota)
@@ -108,7 +108,7 @@ PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOri
RefPtr<SecurityOrigin> origin = prpOrigin;
RefPtr<StorageAreaImpl> storageArea;
- if (storageArea = m_storageAreaMap.get(origin))
+ if ((storageArea = m_storageAreaMap.get(origin)))
return storageArea.release();
storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota);
@@ -119,7 +119,9 @@ PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOri
void StorageNamespaceImpl::close()
{
ASSERT(isMainThread());
- ASSERT(!m_isShutdown);
+
+ if (m_isShutdown)
+ return;
// If we're session storage, we shouldn't need to do any work here.
if (m_storageType == SessionStorage) {
diff --git a/WebCore/storage/StorageNamespaceImpl.h b/WebCore/storage/StorageNamespaceImpl.h
index b81b55a..5221add 100644
--- a/WebCore/storage/StorageNamespaceImpl.h
+++ b/WebCore/storage/StorageNamespaceImpl.h
@@ -43,7 +43,7 @@ namespace WebCore {
class StorageNamespaceImpl : public StorageNamespace {
public:
static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
- static PassRefPtr<StorageNamespace> sessionStorageNamespace();
+ static PassRefPtr<StorageNamespace> sessionStorageNamespace(unsigned quota);
virtual ~StorageNamespaceImpl();
virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>);
diff --git a/WebCore/storage/StorageSyncManager.cpp b/WebCore/storage/StorageSyncManager.cpp
index d9641b7..1cf8306 100644
--- a/WebCore/storage/StorageSyncManager.cpp
+++ b/WebCore/storage/StorageSyncManager.cpp
@@ -28,7 +28,6 @@
#if ENABLE(DOM_STORAGE)
-#include "CString.h"
#include "EventNames.h"
#include "FileSystem.h"
#include "Frame.h"
@@ -38,6 +37,7 @@
#include "Page.h"
#include "PageGroup.h"
#include "StorageAreaSync.h"
+#include <wtf/text/CString.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
@@ -100,6 +100,13 @@ void StorageSyncManager::scheduleSync(PassRefPtr<StorageAreaSync> area)
m_thread->scheduleTask(LocalStorageTask::createSync(area.get()));
}
+void StorageSyncManager::scheduleDeleteEmptyDatabase(PassRefPtr<StorageAreaSync> area)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_thread);
+ if (m_thread)
+ m_thread->scheduleTask(LocalStorageTask::createDeleteEmptyDatabase(area.get()));
+}
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
diff --git a/WebCore/storage/StorageSyncManager.h b/WebCore/storage/StorageSyncManager.h
index e2dfa76..6fbb75d 100644
--- a/WebCore/storage/StorageSyncManager.h
+++ b/WebCore/storage/StorageSyncManager.h
@@ -47,6 +47,7 @@ namespace WebCore {
bool scheduleImport(PassRefPtr<StorageAreaSync>);
void scheduleSync(PassRefPtr<StorageAreaSync>);
+ void scheduleDeleteEmptyDatabase(PassRefPtr<StorageAreaSync>);
void close();
diff --git a/WebCore/storage/chromium/DatabaseObserver.h b/WebCore/storage/chromium/DatabaseObserver.h
index 535c0d2..96b5972 100644
--- a/WebCore/storage/chromium/DatabaseObserver.h
+++ b/WebCore/storage/chromium/DatabaseObserver.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,19 +31,26 @@
#ifndef DatabaseObserver_h
#define DatabaseObserver_h
+#if ENABLE(DATABASE)
+
namespace WebCore {
-class Database;
+class AbstractDatabase;
+class ScriptExecutionContext;
+class String;
// The implementation of this class is in the WebKit API (Chromium source tree)
-// in webkit/api/src/DatabaseObserver.cpp.
+// in WebKit/chromium/src/DatabaseObserver.cpp.
class DatabaseObserver {
public:
- static void databaseOpened(Database*);
- static void databaseModified(Database*);
- static void databaseClosed(Database*);
+ static bool canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long);
+ static void databaseOpened(AbstractDatabase*);
+ static void databaseModified(AbstractDatabase*);
+ static void databaseClosed(AbstractDatabase*);
};
}
+#endif // ENABLE(DATABASE)
+
#endif // DatabaseObserver_h
diff --git a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
index ac58e07..aad4ed9 100644
--- a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
+++ b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,37 +31,34 @@
#include "config.h"
#include "DatabaseTracker.h"
-#include "CString.h"
-#include "Database.h"
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
#include "DatabaseObserver.h"
-#include "DatabaseThread.h"
#include "QuotaTracker.h"
+#include "PlatformString.h"
#include "ScriptExecutionContext.h"
#include "SecurityOrigin.h"
#include "SecurityOriginHash.h"
#include "SQLiteFileSystem.h"
-#include <wtf/HashSet.h>
-#include <wtf/MainThread.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
DatabaseTracker& DatabaseTracker::tracker()
{
- DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ());
+ DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, (""));
return tracker;
}
-DatabaseTracker::DatabaseTracker()
+DatabaseTracker::DatabaseTracker(const String&)
{
SQLiteFileSystem::registerSQLiteVFS();
}
-bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long)
+bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* scriptExecutionContext, const String& name, const String& displayName, unsigned long estimatedSize)
{
- // In Chromium, a database can always be established (even though we might not
- // be able to write anything to it if the quota for this origin was exceeded)
- return true;
+ return DatabaseObserver::canEstablishDatabase(scriptExecutionContext, name, displayName, estimatedSize);
}
void DatabaseTracker::setDatabaseDetails(SecurityOrigin*, const String&, const String&, unsigned long)
@@ -74,7 +71,7 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return origin->databaseIdentifier() + "/" + name + "#";
}
-void DatabaseTracker::addOpenDatabase(Database* database)
+void DatabaseTracker::addOpenDatabase(AbstractDatabase* database)
{
ASSERT(database->scriptExecutionContext()->isContextThread());
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
@@ -101,7 +98,7 @@ void DatabaseTracker::addOpenDatabase(Database* database)
class TrackerRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
public:
- static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
+ static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<AbstractDatabase> database)
{
return new TrackerRemoveOpenDatabaseTask(database);
}
@@ -112,15 +109,15 @@ public:
}
private:
- TrackerRemoveOpenDatabaseTask(PassRefPtr<Database> database)
+ TrackerRemoveOpenDatabaseTask(PassRefPtr<AbstractDatabase> database)
: m_database(database)
{
}
- RefPtr<Database> m_database;
+ RefPtr<AbstractDatabase> m_database;
};
-void DatabaseTracker::removeOpenDatabase(Database* database)
+void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database)
{
if (!database->scriptExecutionContext()->isContextThread()) {
database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database));
@@ -149,7 +146,7 @@ void DatabaseTracker::removeOpenDatabase(Database* database)
}
-void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases)
+void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases)
{
MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
if (!m_openDatabaseMap)
@@ -167,9 +164,8 @@ void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam
databases->add(*it);
}
-unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
+unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
{
- ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
unsigned long long spaceAvailable = 0;
unsigned long long databaseSize = 0;
QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin(
@@ -179,3 +175,5 @@ unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* databa
}
}
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/chromium/IndexedDatabase.cpp b/WebCore/storage/chromium/IndexedDatabase.cpp
new file mode 100644
index 0000000..6f53f92
--- /dev/null
+++ b/WebCore/storage/chromium/IndexedDatabase.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "IndexedDatabase.h"
+
+#include "ChromiumBridge.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+PassRefPtr<IndexedDatabase> IndexedDatabase::create()
+{
+ return ChromiumBridge::indexedDatabase();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
diff --git a/WebCore/storage/chromium/QuotaTracker.cpp b/WebCore/storage/chromium/QuotaTracker.cpp
index b49639d..3f48682 100644
--- a/WebCore/storage/chromium/QuotaTracker.cpp
+++ b/WebCore/storage/chromium/QuotaTracker.cpp
@@ -31,7 +31,8 @@
#include "config.h"
#include "QuotaTracker.h"
-#include "CString.h"
+#if ENABLE(DATABASE)
+
#include <wtf/StdLibExtras.h>
namespace WebCore {
@@ -67,3 +68,5 @@ void QuotaTracker::updateDatabaseSizeAndSpaceAvailableToOrigin(
}
}
+
+#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/chromium/QuotaTracker.h b/WebCore/storage/chromium/QuotaTracker.h
index 9146910..b913563 100644
--- a/WebCore/storage/chromium/QuotaTracker.h
+++ b/WebCore/storage/chromium/QuotaTracker.h
@@ -31,7 +31,9 @@
#ifndef QuotaTracker_h
#define QuotaTracker_h
-#include "CString.h"
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
#include "SecurityOrigin.h"
#include "StringHash.h"
#include <wtf/HashMap.h>
@@ -60,4 +62,6 @@ private:
}
+#endif // ENABLE(DATABASE)
+
#endif // QuotaTracker_h
diff --git a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
index a10ca3e..6a10821 100644
--- a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
+++ b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
@@ -31,18 +31,17 @@
#include "config.h"
#include "SQLTransactionClient.h"
-#include "Database.h"
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
#include "DatabaseObserver.h"
-#include "DatabaseThread.h"
-#include "Document.h"
-#include "SQLTransaction.h"
-#include <wtf/MainThread.h>
+#include "ScriptExecutionContext.h"
namespace WebCore {
class NotifyDatabaseChangedTask : public ScriptExecutionContext::Task {
public:
- static PassOwnPtr<NotifyDatabaseChangedTask> create(Database *database)
+ static PassOwnPtr<NotifyDatabaseChangedTask> create(AbstractDatabase *database)
{
return new NotifyDatabaseChangedTask(database);
}
@@ -53,35 +52,38 @@ public:
}
private:
- NotifyDatabaseChangedTask(PassRefPtr<Database> database)
+ NotifyDatabaseChangedTask(PassRefPtr<AbstractDatabase> database)
: m_database(database)
{
}
- RefPtr<Database> m_database;
+ RefPtr<AbstractDatabase> m_database;
};
-void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
+void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database)
{
- ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
- if (!transaction->isReadOnly()) {
- transaction->database()->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(transaction->database()));
+ if (!database->scriptExecutionContext()->isContextThread()) {
+ database->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(database));
+ return;
}
+
+ WebCore::DatabaseObserver::databaseModified(database);
}
-void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
+void SQLTransactionClient::didExecuteStatement(AbstractDatabase* database)
{
// This method is called after executing every statement that changes the DB.
// Chromium doesn't need to do anything at that point.
- ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
}
-bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
+bool SQLTransactionClient::didExceedQuota(AbstractDatabase* database)
{
// Chromium does not allow users to manually change the quota for an origin (for now, at least).
// Don't do anything.
- ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
+ ASSERT(database->scriptExecutionContext()->isContextThread());
return false;
}
}
+
+#endif // ENABLE(DATABASE)