summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/storage
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/storage')
-rw-r--r--Source/WebCore/storage/AbstractDatabase.cpp497
-rw-r--r--Source/WebCore/storage/AbstractDatabase.h132
-rw-r--r--Source/WebCore/storage/ChangeVersionWrapper.cpp83
-rw-r--r--Source/WebCore/storage/ChangeVersionWrapper.h62
-rw-r--r--Source/WebCore/storage/Database.cpp421
-rw-r--r--Source/WebCore/storage/Database.h120
-rw-r--r--Source/WebCore/storage/Database.idl42
-rw-r--r--Source/WebCore/storage/DatabaseAuthorizer.cpp438
-rw-r--r--Source/WebCore/storage/DatabaseAuthorizer.h126
-rw-r--r--Source/WebCore/storage/DatabaseCallback.h54
-rw-r--r--Source/WebCore/storage/DatabaseCallback.idl37
-rw-r--r--Source/WebCore/storage/DatabaseDetails.h82
-rw-r--r--Source/WebCore/storage/DatabaseSync.cpp199
-rw-r--r--Source/WebCore/storage/DatabaseSync.h75
-rw-r--r--Source/WebCore/storage/DatabaseSync.idl44
-rw-r--r--Source/WebCore/storage/DatabaseTask.cpp184
-rw-r--r--Source/WebCore/storage/DatabaseTask.h175
-rw-r--r--Source/WebCore/storage/DatabaseThread.cpp185
-rw-r--r--Source/WebCore/storage/DatabaseThread.h95
-rw-r--r--Source/WebCore/storage/DatabaseTracker.cpp1108
-rw-r--r--Source/WebCore/storage/DatabaseTracker.h179
-rw-r--r--Source/WebCore/storage/DatabaseTrackerClient.h50
-rw-r--r--Source/WebCore/storage/IDBAbortEvent.cpp55
-rw-r--r--Source/WebCore/storage/IDBAbortEvent.h57
-rw-r--r--Source/WebCore/storage/IDBAny.cpp173
-rw-r--r--Source/WebCore/storage/IDBAny.h121
-rw-r--r--Source/WebCore/storage/IDBAny.idl34
-rw-r--r--Source/WebCore/storage/IDBCallbacks.h66
-rw-r--r--Source/WebCore/storage/IDBCompleteEvent.cpp55
-rw-r--r--Source/WebCore/storage/IDBCompleteEvent.h57
-rw-r--r--Source/WebCore/storage/IDBCursor.cpp101
-rw-r--r--Source/WebCore/storage/IDBCursor.h84
-rw-r--r--Source/WebCore/storage/IDBCursor.idl48
-rw-r--r--Source/WebCore/storage/IDBCursorBackendImpl.cpp199
-rw-r--r--Source/WebCore/storage/IDBCursorBackendImpl.h98
-rw-r--r--Source/WebCore/storage/IDBCursorBackendInterface.h61
-rw-r--r--Source/WebCore/storage/IDBDatabase.cpp155
-rw-r--r--Source/WebCore/storage/IDBDatabase.h83
-rw-r--r--Source/WebCore/storage/IDBDatabase.idl47
-rw-r--r--Source/WebCore/storage/IDBDatabaseBackendImpl.cpp294
-rw-r--r--Source/WebCore/storage/IDBDatabaseBackendImpl.h103
-rw-r--r--Source/WebCore/storage/IDBDatabaseBackendInterface.h68
-rw-r--r--Source/WebCore/storage/IDBDatabaseError.h72
-rw-r--r--Source/WebCore/storage/IDBDatabaseError.idl35
-rw-r--r--Source/WebCore/storage/IDBDatabaseException.h77
-rw-r--r--Source/WebCore/storage/IDBDatabaseException.idl55
-rw-r--r--Source/WebCore/storage/IDBErrorEvent.cpp58
-rw-r--r--Source/WebCore/storage/IDBErrorEvent.h66
-rw-r--r--Source/WebCore/storage/IDBErrorEvent.idl37
-rw-r--r--Source/WebCore/storage/IDBEvent.cpp55
-rw-r--r--Source/WebCore/storage/IDBEvent.h59
-rw-r--r--Source/WebCore/storage/IDBEvent.idl36
-rw-r--r--Source/WebCore/storage/IDBFactory.cpp83
-rw-r--r--Source/WebCore/storage/IDBFactory.h70
-rw-r--r--Source/WebCore/storage/IDBFactory.idl35
-rw-r--r--Source/WebCore/storage/IDBFactoryBackendImpl.cpp240
-rw-r--r--Source/WebCore/storage/IDBFactoryBackendImpl.h79
-rw-r--r--Source/WebCore/storage/IDBFactoryBackendInterface.cpp52
-rw-r--r--Source/WebCore/storage/IDBFactoryBackendInterface.h61
-rw-r--r--Source/WebCore/storage/IDBIndex.cpp115
-rw-r--r--Source/WebCore/storage/IDBIndex.h75
-rw-r--r--Source/WebCore/storage/IDBIndex.idl46
-rw-r--r--Source/WebCore/storage/IDBIndexBackendImpl.cpp210
-rw-r--r--Source/WebCore/storage/IDBIndexBackendImpl.h97
-rw-r--r--Source/WebCore/storage/IDBIndexBackendInterface.h61
-rw-r--r--Source/WebCore/storage/IDBKey.cpp186
-rw-r--r--Source/WebCore/storage/IDBKey.h127
-rw-r--r--Source/WebCore/storage/IDBKey.idl34
-rw-r--r--Source/WebCore/storage/IDBKeyPath.cpp269
-rw-r--r--Source/WebCore/storage/IDBKeyPath.h64
-rw-r--r--Source/WebCore/storage/IDBKeyPathBackendImpl.cpp40
-rw-r--r--Source/WebCore/storage/IDBKeyPathBackendImpl.h47
-rw-r--r--Source/WebCore/storage/IDBKeyRange.cpp86
-rw-r--r--Source/WebCore/storage/IDBKeyRange.h73
-rw-r--r--Source/WebCore/storage/IDBKeyRange.idl43
-rw-r--r--Source/WebCore/storage/IDBObjectStore.cpp154
-rw-r--r--Source/WebCore/storage/IDBObjectStore.h92
-rw-r--r--Source/WebCore/storage/IDBObjectStore.idl52
-rw-r--r--Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp501
-rw-r--r--Source/WebCore/storage/IDBObjectStoreBackendImpl.h112
-rw-r--r--Source/WebCore/storage/IDBObjectStoreBackendInterface.h69
-rw-r--r--Source/WebCore/storage/IDBPendingTransactionMonitor.cpp73
-rw-r--r--Source/WebCore/storage/IDBPendingTransactionMonitor.h63
-rw-r--r--Source/WebCore/storage/IDBRequest.cpp206
-rw-r--r--Source/WebCore/storage/IDBRequest.h117
-rw-r--r--Source/WebCore/storage/IDBRequest.idl55
-rw-r--r--Source/WebCore/storage/IDBSQLiteDatabase.cpp48
-rw-r--r--Source/WebCore/storage/IDBSQLiteDatabase.h62
-rw-r--r--Source/WebCore/storage/IDBSuccessEvent.cpp61
-rw-r--r--Source/WebCore/storage/IDBSuccessEvent.h62
-rw-r--r--Source/WebCore/storage/IDBSuccessEvent.idl36
-rw-r--r--Source/WebCore/storage/IDBTimeoutEvent.cpp55
-rw-r--r--Source/WebCore/storage/IDBTimeoutEvent.h57
-rw-r--r--Source/WebCore/storage/IDBTransaction.cpp175
-rw-r--r--Source/WebCore/storage/IDBTransaction.h113
-rw-r--r--Source/WebCore/storage/IDBTransaction.idl58
-rw-r--r--Source/WebCore/storage/IDBTransactionBackendImpl.cpp216
-rw-r--r--Source/WebCore/storage/IDBTransactionBackendImpl.h97
-rw-r--r--Source/WebCore/storage/IDBTransactionBackendInterface.h64
-rw-r--r--Source/WebCore/storage/IDBTransactionCallbacks.h52
-rw-r--r--Source/WebCore/storage/IDBTransactionCoordinator.cpp114
-rw-r--r--Source/WebCore/storage/IDBTransactionCoordinator.h73
-rw-r--r--Source/WebCore/storage/LocalStorageTask.cpp78
-rw-r--r--Source/WebCore/storage/LocalStorageTask.h66
-rw-r--r--Source/WebCore/storage/LocalStorageThread.cpp104
-rw-r--r--Source/WebCore/storage/LocalStorageThread.h70
-rw-r--r--Source/WebCore/storage/OriginQuotaManager.cpp137
-rw-r--r--Source/WebCore/storage/OriginQuotaManager.h75
-rw-r--r--Source/WebCore/storage/OriginUsageRecord.cpp104
-rw-r--r--Source/WebCore/storage/OriginUsageRecord.h70
-rw-r--r--Source/WebCore/storage/SQLError.h67
-rw-r--r--Source/WebCore/storage/SQLError.idl49
-rw-r--r--Source/WebCore/storage/SQLException.h72
-rw-r--r--Source/WebCore/storage/SQLException.idl51
-rw-r--r--Source/WebCore/storage/SQLResultSet.cpp82
-rw-r--r--Source/WebCore/storage/SQLResultSet.h66
-rw-r--r--Source/WebCore/storage/SQLResultSet.idl48
-rw-r--r--Source/WebCore/storage/SQLResultSetRowList.cpp48
-rw-r--r--Source/WebCore/storage/SQLResultSetRowList.h62
-rw-r--r--Source/WebCore/storage/SQLResultSetRowList.idl39
-rw-r--r--Source/WebCore/storage/SQLStatement.cpp203
-rw-r--r--Source/WebCore/storage/SQLStatement.h84
-rw-r--r--Source/WebCore/storage/SQLStatementCallback.h50
-rw-r--r--Source/WebCore/storage/SQLStatementCallback.idl36
-rw-r--r--Source/WebCore/storage/SQLStatementErrorCallback.h51
-rw-r--r--Source/WebCore/storage/SQLStatementErrorCallback.idl36
-rw-r--r--Source/WebCore/storage/SQLStatementSync.cpp126
-rw-r--r--Source/WebCore/storage/SQLStatementSync.h63
-rw-r--r--Source/WebCore/storage/SQLTransaction.cpp596
-rw-r--r--Source/WebCore/storage/SQLTransaction.h137
-rw-r--r--Source/WebCore/storage/SQLTransaction.idl38
-rw-r--r--Source/WebCore/storage/SQLTransactionCallback.h50
-rw-r--r--Source/WebCore/storage/SQLTransactionCallback.idl36
-rw-r--r--Source/WebCore/storage/SQLTransactionClient.cpp65
-rw-r--r--Source/WebCore/storage/SQLTransactionClient.h55
-rw-r--r--Source/WebCore/storage/SQLTransactionCoordinator.cpp130
-rw-r--r--Source/WebCore/storage/SQLTransactionCoordinator.h68
-rw-r--r--Source/WebCore/storage/SQLTransactionErrorCallback.h50
-rw-r--r--Source/WebCore/storage/SQLTransactionErrorCallback.idl36
-rw-r--r--Source/WebCore/storage/SQLTransactionSync.cpp212
-rw-r--r--Source/WebCore/storage/SQLTransactionSync.h83
-rw-r--r--Source/WebCore/storage/SQLTransactionSync.idl40
-rw-r--r--Source/WebCore/storage/SQLTransactionSyncCallback.h53
-rw-r--r--Source/WebCore/storage/SQLTransactionSyncCallback.idl38
-rw-r--r--Source/WebCore/storage/Storage.cpp116
-rw-r--r--Source/WebCore/storage/Storage.h69
-rw-r--r--Source/WebCore/storage/Storage.idl44
-rw-r--r--Source/WebCore/storage/StorageArea.h63
-rw-r--r--Source/WebCore/storage/StorageAreaImpl.cpp242
-rw-r--r--Source/WebCore/storage/StorageAreaImpl.h84
-rw-r--r--Source/WebCore/storage/StorageAreaSync.cpp432
-rw-r--r--Source/WebCore/storage/StorageAreaSync.h106
-rw-r--r--Source/WebCore/storage/StorageEvent.cpp79
-rw-r--r--Source/WebCore/storage/StorageEvent.h72
-rw-r--r--Source/WebCore/storage/StorageEvent.idl42
-rw-r--r--Source/WebCore/storage/StorageEventDispatcher.cpp89
-rw-r--r--Source/WebCore/storage/StorageEventDispatcher.h54
-rw-r--r--Source/WebCore/storage/StorageMap.cpp187
-rw-r--r--Source/WebCore/storage/StorageMap.h76
-rw-r--r--Source/WebCore/storage/StorageNamespace.cpp52
-rw-r--r--Source/WebCore/storage/StorageNamespace.h63
-rw-r--r--Source/WebCore/storage/StorageNamespaceImpl.cpp172
-rw-r--r--Source/WebCore/storage/StorageNamespaceImpl.h80
-rw-r--r--Source/WebCore/storage/StorageSyncManager.cpp112
-rw-r--r--Source/WebCore/storage/StorageSyncManager.h72
-rw-r--r--Source/WebCore/storage/chromium/DatabaseObserver.h57
-rw-r--r--Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp208
-rw-r--r--Source/WebCore/storage/chromium/IDBFactoryBackendInterface.cpp49
-rw-r--r--Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp42
-rw-r--r--Source/WebCore/storage/chromium/QuotaTracker.cpp72
-rw-r--r--Source/WebCore/storage/chromium/QuotaTracker.h67
-rw-r--r--Source/WebCore/storage/chromium/SQLTransactionClientChromium.cpp89
-rw-r--r--Source/WebCore/storage/wince/DatabaseThreadWinCE.cpp95
-rw-r--r--Source/WebCore/storage/wince/DatabaseThreadWinCE.h65
-rw-r--r--Source/WebCore/storage/wince/LocalStorageThreadWinCE.cpp83
-rw-r--r--Source/WebCore/storage/wince/LocalStorageThreadWinCE.h58
176 files changed, 18742 insertions, 0 deletions
diff --git a/Source/WebCore/storage/AbstractDatabase.cpp b/Source/WebCore/storage/AbstractDatabase.cpp
new file mode 100644
index 0000000..951b621
--- /dev/null
+++ b/Source/WebCore/storage/AbstractDatabase.cpp
@@ -0,0 +1,497 @@
+/*
+ * 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 <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.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();
+}
+
+void AbstractDatabase::setAuthorizerPermissions(int permissions)
+{
+ ASSERT(m_databaseAuthorizer);
+ m_databaseAuthorizer->setPermissions(permissions);
+}
+
+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();
+}
+
+void AbstractDatabase::interrupt()
+{
+ m_sqliteDatabase.interrupt();
+}
+
+bool AbstractDatabase::isInterrupted()
+{
+ MutexLocker locker(m_sqliteDatabase.databaseMutex());
+ return m_sqliteDatabase.isInterrupted();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/AbstractDatabase.h b/Source/WebCore/storage/AbstractDatabase.h
new file mode 100644
index 0000000..bd5d0db
--- /dev/null
+++ b/Source/WebCore/storage/AbstractDatabase.h
@@ -0,0 +1,132 @@
+/*
+ * 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();
+ void interrupt();
+ bool isInterrupted();
+
+ // 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();
+ void setAuthorizerPermissions(int permissions);
+ 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/Source/WebCore/storage/ChangeVersionWrapper.cpp b/Source/WebCore/storage/ChangeVersionWrapper.cpp
new file mode 100644
index 0000000..17be716
--- /dev/null
+++ b/Source/WebCore/storage/ChangeVersionWrapper.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 Apple 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 "ChangeVersionWrapper.h"
+
+#if ENABLE(DATABASE)
+#include "Database.h"
+#include "SQLError.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ChangeVersionWrapper::ChangeVersionWrapper(const String& oldVersion, const String& newVersion)
+ : m_oldVersion(oldVersion.crossThreadString())
+ , m_newVersion(newVersion.crossThreadString())
+{
+}
+
+bool ChangeVersionWrapper::performPreflight(SQLTransaction* transaction)
+{
+ ASSERT(transaction && transaction->database());
+
+ String actualVersion;
+
+ if (!transaction->database()->getVersionFromDatabase(actualVersion)) {
+ LOG_ERROR("Unable to retrieve actual current version from 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(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match");
+ return false;
+ }
+
+ return true;
+}
+
+bool ChangeVersionWrapper::performPostflight(SQLTransaction* transaction)
+{
+ ASSERT(transaction && transaction->database());
+
+ if (!transaction->database()->setVersionInDatabase(m_newVersion)) {
+ LOG_ERROR("Unable to set new version in database");
+ m_sqlError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to set new version in database");
+ return false;
+ }
+
+ transaction->database()->setExpectedVersion(m_newVersion);
+
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/ChangeVersionWrapper.h b/Source/WebCore/storage/ChangeVersionWrapper.h
new file mode 100644
index 0000000..86cc182
--- /dev/null
+++ b/Source/WebCore/storage/ChangeVersionWrapper.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 Apple 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 ChangeVersionWrapper_h
+#define ChangeVersionWrapper_h
+
+#if ENABLE(DATABASE)
+
+#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)); }
+
+ virtual bool performPreflight(SQLTransaction*);
+ virtual bool performPostflight(SQLTransaction*);
+
+ virtual SQLError* sqlError() const { return m_sqlError.get(); }
+
+private:
+ ChangeVersionWrapper(const String& oldVersion, const String& newVersion);
+
+ String m_oldVersion;
+ String m_newVersion;
+ RefPtr<SQLError> m_sqlError;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // ChangeVersionWrapper_h
diff --git a/Source/WebCore/storage/Database.cpp b/Source/WebCore/storage/Database.cpp
new file mode 100644
index 0000000..920f75b
--- /dev/null
+++ b/Source/WebCore/storage/Database.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 "Database.h"
+
+#if ENABLE(DATABASE)
+#include "ChangeVersionWrapper.h"
+#include "DatabaseCallback.h"
+#include "DatabaseTask.h"
+#include "DatabaseThread.h"
+#include "DatabaseTracker.h"
+#include "Document.h"
+#include "InspectorController.h"
+#include "Logging.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "SQLTransactionCallback.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionCoordinator.h"
+#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>
+#include <wtf/text/CString.h>
+
+#if USE(JSC)
+#include "JSDOMWindow.h"
+#endif
+
+namespace WebCore {
+
+class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> creationCallback)
+ {
+ return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback));
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_creationCallback->handleEvent(m_database.get());
+ }
+
+private:
+ DatabaseCreationCallbackTask(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> callback)
+ : m_database(database)
+ , m_creationCallback(callback)
+ {
+ }
+
+ 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, PassRefPtr<DatabaseCallback> creationCallback,
+ ExceptionCode& e)
+{
+ 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<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize));
+
+ 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());
+ DatabaseTracker::tracker().removeOpenDatabase(database.get());
+ return 0;
+ }
+
+ DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+
+ context->setHasOpenDatabases();
+#if ENABLE(INSPECTOR)
+ if (context->isDocument()) {
+ Document* document = static_cast<Document*>(context);
+ if (Page* page = document->page())
+ page->inspectorController()->didOpenDatabase(database, context->securityOrigin()->host(), name, expectedVersion);
+ }
+#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)
+ : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize)
+ , m_transactionInProgress(false)
+ , m_isTransactionQueueEnabled(true)
+ , m_deleted(false)
+{
+ m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->threadsafeCopy();
+
+ ScriptController::initializeThreading();
+ ASSERT(m_scriptExecutionContext->databaseThread());
+}
+
+class DerefContextTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DerefContextTask> create(PassRefPtr<ScriptExecutionContext> context)
+ {
+ return adoptPtr(new DerefContextTask(context));
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ 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()) {
+ // 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()));
+ }
+}
+
+String Database::version() const
+{
+ if (m_deleted)
+ return String();
+ return AbstractDatabase::version();
+}
+
+bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode& e)
+{
+ DatabaseTaskSynchronizer synchronizer;
+ if (!m_scriptExecutionContext->databaseThread() || m_scriptExecutionContext->databaseThread()->terminationRequested(&synchronizer))
+ return false;
+
+ bool success = false;
+ OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, e, success);
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
+
+ return success;
+}
+
+void Database::markAsDeletedAndClose()
+{
+ if (m_deleted || !m_scriptExecutionContext->databaseThread())
+ return;
+
+ LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
+ m_deleted = true;
+
+ DatabaseTaskSynchronizer synchronizer;
+ if (m_scriptExecutionContext->databaseThread()->terminationRequested(&synchronizer)) {
+ LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
+ return;
+ }
+
+ OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
+}
+
+void Database::close()
+{
+ ASSERT(m_scriptExecutionContext->databaseThread());
+ ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
+
+ {
+ MutexLocker locker(m_transactionInProgressMutex);
+ m_isTransactionQueueEnabled = false;
+ m_transactionInProgress = false;
+ }
+
+ closeDatabase();
+
+ // 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::closeImmediately()
+{
+ DatabaseThread* databaseThread = scriptExecutionContext()->databaseThread();
+ if (databaseThread && !databaseThread->terminationRequested() && opened())
+ databaseThread->scheduleImmediateTask(DatabaseCloseTask::create(this, 0));
+}
+
+unsigned long long Database::maximumSize() const
+{
+ return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
+}
+
+bool Database::performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode& e)
+{
+ if (AbstractDatabase::performOpenAndVerify(setVersionInNewDatabase, e)) {
+ if (m_scriptExecutionContext->databaseThread())
+ m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
+
+ return true;
+ }
+
+ return false;
+}
+
+void Database::changeVersion(const String& oldVersion, const String& newVersion,
+ PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ PassRefPtr<VoidCallback> successCallback)
+{
+ m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion)));
+ MutexLocker locker(m_transactionInProgressMutex);
+ if (!m_transactionInProgress)
+ scheduleTransaction();
+}
+
+void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
+{
+ runTransaction(callback, errorCallback, successCallback, false);
+}
+
+void Database::readTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
+{
+ runTransaction(callback, errorCallback, successCallback, true);
+}
+
+void Database::runTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ PassRefPtr<VoidCallback> successCallback, bool readOnly)
+{
+ m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly));
+ MutexLocker locker(m_transactionInProgressMutex);
+ if (!m_transactionInProgress)
+ 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.takeFirst();
+ }
+
+ if (transaction && m_scriptExecutionContext->databaseThread()) {
+ OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
+ LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
+ m_transactionInProgress = true;
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
+ } else
+ m_transactionInProgress = false;
+}
+
+void Database::scheduleTransactionStep(SQLTransaction* transaction, bool immediately)
+{
+ if (!m_scriptExecutionContext->databaseThread())
+ return;
+
+ OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
+ LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
+ if (immediately)
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ else
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
+}
+
+class DeliverPendingCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction)
+ {
+ return adoptPtr(new DeliverPendingCallbackTask(transaction));
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_transaction->performPendingCallback();
+ }
+
+private:
+ DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)
+ : m_transaction(transaction)
+ {
+ }
+
+ RefPtr<SQLTransaction> m_transaction;
+};
+
+void Database::scheduleTransactionCallback(SQLTransaction* transaction)
+{
+ m_scriptExecutionContext->postTask(DeliverPendingCallbackTask::create(transaction));
+}
+
+Vector<String> Database::performGetTableNames()
+{
+ disableAuthorizer();
+
+ 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();
+ return Vector<String>();
+ }
+
+ Vector<String> tableNames;
+ int result;
+ while ((result = statement.step()) == SQLResultRow) {
+ String name = statement.getColumnText(0);
+ if (name != databaseInfoTableName())
+ tableNames.append(name);
+ }
+
+ enableAuthorizer();
+
+ if (result != SQLResultDone) {
+ LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
+ return Vector<String>();
+ }
+
+ return tableNames;
+}
+
+SQLTransactionClient* Database::transactionClient() const
+{
+ return m_scriptExecutionContext->databaseThread()->transactionClient();
+}
+
+SQLTransactionCoordinator* Database::transactionCoordinator() const
+{
+ return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
+}
+
+Vector<String> Database::tableNames()
+{
+ // FIXME: Not using threadsafeCopy on these strings looks ok since threads take strict turns
+ // in dealing with them. However, if the code changes, this may not be true anymore.
+ Vector<String> result;
+ DatabaseTaskSynchronizer synchronizer;
+ if (!m_scriptExecutionContext->databaseThread() || m_scriptExecutionContext->databaseThread()->terminationRequested(&synchronizer))
+ return result;
+
+ OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
+ synchronizer.waitForTaskCompletion();
+
+ return result;
+}
+
+SecurityOrigin* Database::securityOrigin() const
+{
+ if (m_scriptExecutionContext->isContextThread())
+ return m_contextThreadSecurityOrigin.get();
+ if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID())
+ return m_databaseThreadSecurityOrigin.get();
+ return 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/Database.h b/Source/WebCore/storage/Database.h
new file mode 100644
index 0000000..47001a4
--- /dev/null
+++ b/Source/WebCore/storage/Database.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 Database_h
+#define Database_h
+
+#if ENABLE(DATABASE)
+#include "AbstractDatabase.h"
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+
+#include <wtf/Deque.h>
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class DatabaseCallback;
+class ScriptExecutionContext;
+class SecurityOrigin;
+class SQLTransaction;
+class SQLTransactionCallback;
+class SQLTransactionClient;
+class SQLTransactionCoordinator;
+class SQLTransactionErrorCallback;
+class VoidCallback;
+
+class Database : public AbstractDatabase {
+public:
+ 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);
+ void readTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback> successCallback);
+
+ // Internal engine support
+ Vector<String> tableNames();
+
+ virtual SecurityOrigin* securityOrigin() const;
+
+ virtual void markAsDeletedAndClose();
+ bool deleted() const { return m_deleted; }
+
+ void close();
+ virtual void closeImmediately();
+
+ unsigned long long databaseSize() const;
+ unsigned long long maximumSize() const;
+
+ void scheduleTransactionCallback(SQLTransaction*);
+ void scheduleTransactionStep(SQLTransaction*, bool immediately = false);
+
+ SQLTransactionClient* transactionClient() const;
+ SQLTransactionCoordinator* transactionCoordinator() const;
+
+private:
+ class DatabaseOpenTask;
+ class DatabaseCloseTask;
+ class DatabaseTransactionTask;
+ class DatabaseTableNamesTask;
+
+ Database(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize);
+ void runTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
+ PassRefPtr<VoidCallback> successCallback, bool readOnly);
+
+ bool openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode&);
+ virtual bool performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode&);
+
+ void inProgressTransactionCompleted();
+ void scheduleTransaction();
+
+ Vector<String> performGetTableNames();
+
+ static void deliverPendingCallback(void*);
+
+ Deque<RefPtr<SQLTransaction> > m_transactionQueue;
+ Mutex m_transactionInProgressMutex;
+ bool m_transactionInProgress;
+ bool m_isTransactionQueueEnabled;
+
+ RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
+
+ bool m_deleted;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // Database_h
diff --git a/Source/WebCore/storage/Database.idl b/Source/WebCore/storage/Database.idl
new file mode 100644
index 0000000..20c2fa1
--- /dev/null
+++ b/Source/WebCore/storage/Database.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Apple 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,
+ OmitConstructor,
+ NoStaticTables
+ ] Database {
+ readonly attribute DOMString version;
+ [RequiresAllArguments=Raise] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in [Callback, Optional] SQLTransactionCallback callback, in [Callback, Optional] SQLTransactionErrorCallback errorCallback, in [Callback, Optional] VoidCallback successCallback);
+ [RequiresAllArguments=Raise] void transaction(in [Callback] SQLTransactionCallback callback, in [Callback, Optional] SQLTransactionErrorCallback errorCallback, in [Callback, Optional] VoidCallback successCallback);
+ [RequiresAllArguments=Raise] void readTransaction(in [Callback] SQLTransactionCallback callback, in [Callback, Optional] SQLTransactionErrorCallback errorCallback, in [Callback, Optional] VoidCallback successCallback);
+ };
+
+}
diff --git a/Source/WebCore/storage/DatabaseAuthorizer.cpp b/Source/WebCore/storage/DatabaseAuthorizer.cpp
new file mode 100644
index 0000000..b90565c
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseAuthorizer.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2007 Apple 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 "DatabaseAuthorizer.h"
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+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();
+}
+
+void DatabaseAuthorizer::reset()
+{
+ m_lastActionWasInsert = false;
+ m_lastActionChangedDatabase = false;
+ m_permissions = ReadWriteMask;
+}
+
+void DatabaseAuthorizer::resetDeletes()
+{
+ m_hadDeletes = false;
+}
+
+void DatabaseAuthorizer::addWhitelistedFunctions()
+{
+ // SQLite functions used to help implement some operations
+ // ALTER TABLE helpers
+ m_whitelistedFunctions.add("sqlite_rename_table");
+ m_whitelistedFunctions.add("sqlite_rename_trigger");
+ // GLOB helpers
+ m_whitelistedFunctions.add("glob");
+
+ // SQLite core functions
+ m_whitelistedFunctions.add("abs");
+ m_whitelistedFunctions.add("changes");
+ m_whitelistedFunctions.add("coalesce");
+ m_whitelistedFunctions.add("glob");
+ m_whitelistedFunctions.add("ifnull");
+ m_whitelistedFunctions.add("hex");
+ m_whitelistedFunctions.add("last_insert_rowid");
+ m_whitelistedFunctions.add("length");
+ m_whitelistedFunctions.add("like");
+ m_whitelistedFunctions.add("lower");
+ m_whitelistedFunctions.add("ltrim");
+ m_whitelistedFunctions.add("max");
+ m_whitelistedFunctions.add("min");
+ m_whitelistedFunctions.add("nullif");
+ m_whitelistedFunctions.add("quote");
+ m_whitelistedFunctions.add("replace");
+ m_whitelistedFunctions.add("round");
+ m_whitelistedFunctions.add("rtrim");
+ m_whitelistedFunctions.add("soundex");
+ m_whitelistedFunctions.add("sqlite_source_id");
+ m_whitelistedFunctions.add("sqlite_version");
+ m_whitelistedFunctions.add("substr");
+ m_whitelistedFunctions.add("total_changes");
+ m_whitelistedFunctions.add("trim");
+ m_whitelistedFunctions.add("typeof");
+ m_whitelistedFunctions.add("upper");
+ m_whitelistedFunctions.add("zeroblob");
+
+ // SQLite date and time functions
+ m_whitelistedFunctions.add("date");
+ m_whitelistedFunctions.add("time");
+ m_whitelistedFunctions.add("datetime");
+ m_whitelistedFunctions.add("julianday");
+ m_whitelistedFunctions.add("strftime");
+
+ // SQLite aggregate functions
+ // max() and min() are already in the list
+ m_whitelistedFunctions.add("avg");
+ m_whitelistedFunctions.add("count");
+ m_whitelistedFunctions.add("group_concat");
+ m_whitelistedFunctions.add("sum");
+ m_whitelistedFunctions.add("total");
+
+ // SQLite FTS functions
+ m_whitelistedFunctions.add("match");
+ m_whitelistedFunctions.add("snippet");
+ m_whitelistedFunctions.add("offsets");
+ m_whitelistedFunctions.add("optimize");
+
+ // SQLite ICU functions
+ // like(), lower() and upper() are already in the list
+ m_whitelistedFunctions.add("regexp");
+}
+
+int DatabaseAuthorizer::createTable(const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createTempTable(const String& tableName)
+{
+ // SQLITE_CREATE_TEMP_TABLE results in a UPDATE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_TABLE in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropTable(const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropTempTable(const String& tableName)
+{
+ // SQLITE_DROP_TEMP_TABLE 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_TABLE in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowAlterTable(const String&, const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createIndex(const String&, const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createTempIndex(const String&, const String& tableName)
+{
+ // SQLITE_CREATE_TEMP_INDEX should result in a UPDATE or INSERT operation,
+ // which is not allowed in read-only transactions or private browsing,
+ // so we might as well disallow SQLITE_CREATE_TEMP_INDEX in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropIndex(const String&, const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
+{
+ // SQLITE_DROP_TEMP_INDEX should result in a DELETE operation, which is
+ // not allowed in read-only transactions or private browsing, so we might
+ // as well disallow SQLITE_DROP_TEMP_INDEX in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createTrigger(const String&, const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createTempTrigger(const String&, const String& tableName)
+{
+ // SQLITE_CREATE_TEMP_TRIGGER results in a INSERT operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_TRIGGER in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
+{
+ // SQLITE_DROP_TEMP_TRIGGER 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_TRIGGER in these cases
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::createView(const String&)
+{
+ return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::createTempView(const String&)
+{
+ // SQLITE_CREATE_TEMP_VIEW results in a UPDATE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_VIEW in these cases
+ return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::dropView(const String&)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_hadDeletes = true;
+ return SQLAuthAllow;
+}
+
+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
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_hadDeletes = true;
+ return SQLAuthAllow;
+}
+
+int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ // Allow only the FTS3 extension
+ if (!equalIgnoringCase(moduleName, "fts3"))
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ // Allow only the FTS3 extension
+ if (!equalIgnoringCase(moduleName, "fts3"))
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowDelete(const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ return updateDeletesBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowInsert(const String& tableName)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ m_lastActionWasInsert = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowUpdate(const String& tableName, const String&)
+{
+ if (!allowWrite())
+ return SQLAuthDeny;
+
+ m_lastActionChangedDatabase = true;
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowTransaction()
+{
+ return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+}
+
+int DatabaseAuthorizer::allowRead(const String& tableName, const String&)
+{
+ if (m_permissions & NoAccessMask && m_securityEnabled)
+ return SQLAuthDeny;
+
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowReindex(const String&)
+{
+ return (!allowWrite() ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::allowAnalyze(const String& tableName)
+{
+ return denyBasedOnTableName(tableName);
+}
+
+int DatabaseAuthorizer::allowPragma(const String&, const String&)
+{
+ return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+}
+
+int DatabaseAuthorizer::allowAttach(const String&)
+{
+ return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+}
+
+int DatabaseAuthorizer::allowDetach(const String&)
+{
+ return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow;
+}
+
+int DatabaseAuthorizer::allowFunction(const String& functionName)
+{
+ if (m_securityEnabled && !m_whitelistedFunctions.contains(functionName))
+ return SQLAuthDeny;
+
+ return SQLAuthAllow;
+}
+
+void DatabaseAuthorizer::disable()
+{
+ m_securityEnabled = false;
+}
+
+void DatabaseAuthorizer::enable()
+{
+ m_securityEnabled = true;
+}
+
+bool DatabaseAuthorizer::allowWrite()
+{
+ return !(m_securityEnabled && (m_permissions & ReadOnlyMask || m_permissions & NoAccessMask));
+}
+
+void DatabaseAuthorizer::setReadOnly()
+{
+ m_permissions |= ReadOnlyMask;
+}
+
+void DatabaseAuthorizer::setPermissions(int permissions)
+{
+ m_permissions = permissions;
+}
+
+int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const
+{
+ if (!m_securityEnabled)
+ return SQLAuthAllow;
+
+ // Sadly, normal creates and drops end up affecting sqlite_master in an authorizer callback, so
+ // it will be tough to enforce all of the following policies
+ //if (equalIgnoringCase(tableName, "sqlite_master") || equalIgnoringCase(tableName, "sqlite_temp_master") ||
+ // equalIgnoringCase(tableName, "sqlite_sequence") || equalIgnoringCase(tableName, Database::databaseInfoTableName()))
+ // return SQLAuthDeny;
+
+ 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
+
+#endif
diff --git a/Source/WebCore/storage/DatabaseAuthorizer.h b/Source/WebCore/storage/DatabaseAuthorizer.h
new file mode 100644
index 0000000..da7761d
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseAuthorizer.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 Apple 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 DatabaseAuthorizer_h
+#define DatabaseAuthorizer_h
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+#include <wtf/ThreadSafeShared.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+extern const int SQLAuthAllow;
+extern const int SQLAuthIgnore;
+extern const int SQLAuthDeny;
+
+class DatabaseAuthorizer : public ThreadSafeShared<DatabaseAuthorizer> {
+public:
+
+ enum Permissions {
+ ReadWriteMask = 0,
+ ReadOnlyMask = 1 << 1,
+ NoAccessMask = 1 << 2
+ };
+
+ static PassRefPtr<DatabaseAuthorizer> create(const String& databaseInfoTableName);
+
+ int createTable(const String& tableName);
+ int createTempTable(const String& tableName);
+ int dropTable(const String& tableName);
+ int dropTempTable(const String& tableName);
+ int allowAlterTable(const String& databaseName, const String& tableName);
+
+ int createIndex(const String& indexName, const String& tableName);
+ int createTempIndex(const String& indexName, const String& tableName);
+ int dropIndex(const String& indexName, const String& tableName);
+ int dropTempIndex(const String& indexName, const String& tableName);
+
+ int createTrigger(const String& triggerName, const String& tableName);
+ int createTempTrigger(const String& triggerName, const String& tableName);
+ int dropTrigger(const String& triggerName, const String& tableName);
+ int dropTempTrigger(const String& triggerName, const String& tableName);
+
+ int createView(const String& viewName);
+ int createTempView(const String& viewName);
+ int dropView(const String& viewName);
+ int dropTempView(const String& viewName);
+
+ int createVTable(const String& tableName, const String& moduleName);
+ int dropVTable(const String& tableName, const String& moduleName);
+
+ int allowDelete(const String& tableName);
+ int allowInsert(const String& tableName);
+ int allowUpdate(const String& tableName, const String& columnName);
+ int allowTransaction();
+
+ int allowSelect() { return SQLAuthAllow; }
+ int allowRead(const String& tableName, const String& columnName);
+
+ int allowReindex(const String& indexName);
+ int allowAnalyze(const String& tableName);
+ int allowFunction(const String& functionName);
+ int allowPragma(const String& pragmaName, const String& firstArgument);
+
+ int allowAttach(const String& filename);
+ int allowDetach(const String& databaseName);
+
+ void disable();
+ void enable();
+ void setReadOnly();
+ void setPermissions(int permissions);
+
+ void reset();
+ void resetDeletes();
+
+ bool lastActionWasInsert() const { return m_lastActionWasInsert; }
+ bool lastActionChangedDatabase() const { return m_lastActionChangedDatabase; }
+ bool hadDeletes() const { return m_hadDeletes; }
+
+private:
+ DatabaseAuthorizer(const String& databaseInfoTableName);
+ void addWhitelistedFunctions();
+ int denyBasedOnTableName(const String&) const;
+ int updateDeletesBasedOnTableName(const String&);
+ bool allowWrite();
+
+ int m_permissions;
+ bool m_securityEnabled : 1;
+ bool m_lastActionWasInsert : 1;
+ bool m_lastActionChangedDatabase : 1;
+ bool m_hadDeletes : 1;
+
+ const String m_databaseInfoTableName;
+
+ HashSet<String, CaseFoldingHash> m_whitelistedFunctions;
+};
+
+} // namespace WebCore
+
+#endif // DatabaseAuthorizer_h
diff --git a/Source/WebCore/storage/DatabaseCallback.h b/Source/WebCore/storage/DatabaseCallback.h
new file mode 100644
index 0000000..8ad56ed
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseCallback.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 DatabaseCallback_h
+#define DatabaseCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class Database;
+class DatabaseSync;
+
+class DatabaseCallback : public ThreadSafeShared<DatabaseCallback> {
+public:
+ virtual ~DatabaseCallback() { }
+ virtual bool handleEvent(Database*) = 0;
+ virtual bool handleEvent(DatabaseSync*) = 0;
+};
+
+}
+
+#endif
+
+#endif // DatabaseCallback_h
diff --git a/Source/WebCore/storage/DatabaseCallback.idl b/Source/WebCore/storage/DatabaseCallback.idl
new file mode 100644
index 0000000..c218680
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/DatabaseDetails.h b/Source/WebCore/storage/DatabaseDetails.h
new file mode 100644
index 0000000..c2217af
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseDetails.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 DatabaseDetails_h
+#define DatabaseDetails_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class DatabaseDetails {
+public:
+ DatabaseDetails()
+ : 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)
+ : m_name(databaseName)
+ , m_displayName(displayName)
+ , 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; }
+ uint64_t expectedUsage() const { return m_expectedUsage; }
+ uint64_t currentUsage() const { return m_currentUsage; }
+#ifndef NDEBUG
+ ThreadIdentifier thread() const { return m_thread; }
+#endif
+
+private:
+ String m_name;
+ String m_displayName;
+ uint64_t m_expectedUsage;
+ uint64_t m_currentUsage;
+#ifndef NDEBUG
+ ThreadIdentifier m_thread;
+#endif
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // DatabaseDetails_h
diff --git a/Source/WebCore/storage/DatabaseSync.cpp b/Source/WebCore/storage/DatabaseSync.cpp
new file mode 100644
index 0000000..5634a60
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseSync.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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>
+#include <wtf/text/CString.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(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, ExceptionCode& ec)
+{
+ runTransaction(callback, false, ec);
+}
+
+void DatabaseSync::readTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec)
+{
+ runTransaction(callback, true, ec);
+}
+
+void DatabaseSync::runTransaction(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 adoptPtr(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/Source/WebCore/storage/DatabaseSync.h b/Source/WebCore/storage/DatabaseSync.h
new file mode 100644
index 0000000..6563b23
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseSync.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:
+ *
+ * * 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>, ExceptionCode&);
+ void readTransaction(PassRefPtr<SQLTransactionSyncCallback>, ExceptionCode&);
+
+ virtual void markAsDeletedAndClose();
+ virtual void closeImmediately();
+
+private:
+ DatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ const String& displayName, unsigned long estimatedSize);
+ void runTransaction(PassRefPtr<SQLTransactionSyncCallback>, bool readOnly, ExceptionCode&);
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // DatabaseSync_h
diff --git a/Source/WebCore/storage/DatabaseSync.idl b/Source/WebCore/storage/DatabaseSync.idl
new file mode 100644
index 0000000..0064991
--- /dev/null
+++ b/Source/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;
+ [RequiresAllArguments=Raise] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in [Callback, Optional] SQLTransactionSyncCallback callback) raises(DOMException);
+ [RequiresAllArguments=Raise] void transaction(in [Callback] SQLTransactionSyncCallback callback) raises(DOMException);
+ [RequiresAllArguments=Raise] void readTransaction(in [Callback] SQLTransactionSyncCallback callback) raises(DOMException);
+ };
+
+}
diff --git a/Source/WebCore/storage/DatabaseTask.cpp b/Source/WebCore/storage/DatabaseTask.cpp
new file mode 100644
index 0000000..343ae1e
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseTask.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 "DatabaseTask.h"
+
+#if ENABLE(DATABASE)
+
+#include "Database.h"
+#include "Logging.h"
+
+namespace WebCore {
+
+DatabaseTaskSynchronizer::DatabaseTaskSynchronizer()
+ : m_taskCompleted(false)
+#ifndef NDEBUG
+ , m_hasCheckedForTermination(false)
+#endif
+{
+}
+
+void DatabaseTaskSynchronizer::waitForTaskCompletion()
+{
+ m_synchronousMutex.lock();
+ if (!m_taskCompleted)
+ m_synchronousCondition.wait(m_synchronousMutex);
+ m_synchronousMutex.unlock();
+}
+
+void DatabaseTaskSynchronizer::taskCompleted()
+{
+ m_synchronousMutex.lock();
+ m_taskCompleted = true;
+ m_synchronousCondition.signal();
+ m_synchronousMutex.unlock();
+}
+
+DatabaseTask::DatabaseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
+ : m_database(database)
+ , m_synchronizer(synchronizer)
+#ifndef NDEBUG
+ , m_complete(false)
+#endif
+{
+}
+
+DatabaseTask::~DatabaseTask()
+{
+ ASSERT(m_complete || !m_synchronizer);
+}
+
+void DatabaseTask::performTask()
+{
+ // Database tasks are meant to be used only once, so make sure this one hasn't been performed before.
+ ASSERT(!m_complete);
+
+ LOG(StorageAPI, "Performing %s %p\n", debugTaskName(), this);
+
+ m_database->resetAuthorizer();
+ doPerformTask();
+
+ if (m_synchronizer)
+ m_synchronizer->taskCompleted();
+
+#ifndef NDEBUG
+ m_complete = true;
+#endif
+}
+
+// *** DatabaseOpenTask ***
+// Opens the database file and verifies the version matches the expected version.
+
+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 Database::DatabaseOpenTask::doPerformTask()
+{
+ m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_code);
+}
+
+#ifndef NDEBUG
+const char* Database::DatabaseOpenTask::debugTaskName() const
+{
+ return "DatabaseOpenTask";
+}
+#endif
+
+// *** DatabaseCloseTask ***
+// Closes the database.
+
+Database::DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer)
+ : DatabaseTask(database, synchronizer)
+{
+}
+
+void Database::DatabaseCloseTask::doPerformTask()
+{
+ database()->close();
+}
+
+#ifndef NDEBUG
+const char* Database::DatabaseCloseTask::debugTaskName() const
+{
+ return "DatabaseCloseTask";
+}
+#endif
+
+// *** DatabaseTransactionTask ***
+// Starts a transaction that will report its results via a callback.
+
+Database::DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction)
+ : DatabaseTask(transaction->database(), 0)
+ , m_transaction(transaction)
+{
+}
+
+void Database::DatabaseTransactionTask::doPerformTask()
+{
+ if (m_transaction->performNextStep())
+ m_transaction->database()->inProgressTransactionCompleted();
+}
+
+#ifndef NDEBUG
+const char* Database::DatabaseTransactionTask::debugTaskName() const
+{
+ return "DatabaseTransactionTask";
+}
+#endif
+
+// *** DatabaseTableNamesTask ***
+// Retrieves a list of all tables in the database - for WebInspector support.
+
+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 Database::DatabaseTableNamesTask::doPerformTask()
+{
+ m_tableNames = database()->performGetTableNames();
+}
+
+#ifndef NDEBUG
+const char* Database::DatabaseTableNamesTask::debugTaskName() const
+{
+ return "DatabaseTableNamesTask";
+}
+#endif
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/DatabaseTask.h b/Source/WebCore/storage/DatabaseTask.h
new file mode 100644
index 0000000..b61e465
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseTask.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 DatabaseTask_h
+#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>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// 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 {
+public:
+ DatabaseTaskSynchronizer();
+
+ // Called from main thread to wait until task is completed.
+ void waitForTaskCompletion();
+
+ // Called by the task.
+ void taskCompleted();
+
+#ifndef NDEBUG
+ bool hasCheckedForTermination() const { return m_hasCheckedForTermination; }
+ void setHasCheckedForTermination() { m_hasCheckedForTermination = true; }
+#endif
+
+private:
+ bool m_taskCompleted;
+ Mutex m_synchronousMutex;
+ ThreadCondition m_synchronousCondition;
+#ifndef NDEBUG
+ bool m_hasCheckedForTermination;
+#endif
+};
+
+class DatabaseTask : public Noncopyable {
+public:
+ virtual ~DatabaseTask();
+
+ void performTask();
+
+ Database* database() const { return m_database; }
+#ifndef NDEBUG
+ bool hasSynchronizer() const { return m_synchronizer; }
+ bool hasCheckedForTermination() const { return m_synchronizer->hasCheckedForTermination(); }
+#endif
+
+protected:
+ DatabaseTask(Database*, DatabaseTaskSynchronizer*);
+
+private:
+ virtual void doPerformTask() = 0;
+
+ Database* m_database;
+ DatabaseTaskSynchronizer* m_synchronizer;
+
+#ifndef NDEBUG
+ virtual const char* debugTaskName() const = 0;
+ bool m_complete;
+#endif
+};
+
+class Database::DatabaseOpenTask : public DatabaseTask {
+public:
+ static PassOwnPtr<DatabaseOpenTask> create(Database* db, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
+ {
+ return adoptPtr(new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success));
+ }
+
+private:
+ 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 Database::DatabaseCloseTask : public DatabaseTask {
+public:
+ static PassOwnPtr<DatabaseCloseTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer)
+ {
+ return adoptPtr(new DatabaseCloseTask(db, synchronizer));
+ }
+
+private:
+ DatabaseCloseTask(Database*, DatabaseTaskSynchronizer*);
+
+ virtual void doPerformTask();
+#ifndef NDEBUG
+ virtual const char* debugTaskName() const;
+#endif
+};
+
+class Database::DatabaseTransactionTask : public DatabaseTask {
+public:
+ // Transaction task is never synchronous, so no 'synchronizer' parameter.
+ static PassOwnPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction)
+ {
+ return adoptPtr(new DatabaseTransactionTask(transaction));
+ }
+
+ SQLTransaction* transaction() const { return m_transaction.get(); }
+
+private:
+ DatabaseTransactionTask(PassRefPtr<SQLTransaction>);
+
+ virtual void doPerformTask();
+#ifndef NDEBUG
+ virtual const char* debugTaskName() const;
+#endif
+
+ RefPtr<SQLTransaction> m_transaction;
+};
+
+class Database::DatabaseTableNamesTask : public DatabaseTask {
+public:
+ static PassOwnPtr<DatabaseTableNamesTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
+ {
+ return adoptPtr(new DatabaseTableNamesTask(db, synchronizer, names));
+ }
+
+private:
+ DatabaseTableNamesTask(Database*, DatabaseTaskSynchronizer*, Vector<String>& names);
+
+ virtual void doPerformTask();
+#ifndef NDEBUG
+ virtual const char* debugTaskName() const;
+#endif
+
+ Vector<String>& m_tableNames;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+#endif // DatabaseTask_h
diff --git a/Source/WebCore/storage/DatabaseThread.cpp b/Source/WebCore/storage/DatabaseThread.cpp
new file mode 100644
index 0000000..3b790ee
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseThread.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 "DatabaseThread.h"
+
+#if ENABLE(DATABASE)
+
+#include "AutodrainedPool.h"
+#include "Database.h"
+#include "DatabaseTask.h"
+#include "Logging.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionCoordinator.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+DatabaseThread::DatabaseThread()
+ : m_threadID(0)
+ , m_transactionClient(adoptPtr(new SQLTransactionClient()))
+ , m_transactionCoordinator(adoptPtr(new SQLTransactionCoordinator()))
+ , m_cleanupSync(0)
+{
+ m_selfRef = this;
+}
+
+DatabaseThread::~DatabaseThread()
+{
+ // FIXME: Any cleanup required here? Since the thread deletes itself after running its detached course, I don't think so. Lets be sure.
+ ASSERT(terminationRequested());
+}
+
+bool DatabaseThread::start()
+{
+ MutexLocker lock(m_threadCreationMutex);
+
+ if (m_threadID)
+ return true;
+
+ m_threadID = createThread(DatabaseThread::databaseThreadStart, this, "WebCore: Database");
+
+ return m_threadID;
+}
+
+void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
+{
+ ASSERT(!m_cleanupSync);
+ m_cleanupSync = cleanupSync;
+ LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
+ m_queue.kill();
+}
+
+bool DatabaseThread::terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer) const
+{
+#ifndef NDEBUG
+ if (taskSynchronizer)
+ taskSynchronizer->setHasCheckedForTermination();
+#else
+ UNUSED_PARAM(taskSynchronizer);
+#endif
+
+ return m_queue.killed();
+}
+
+void* DatabaseThread::databaseThreadStart(void* vDatabaseThread)
+{
+ DatabaseThread* dbThread = static_cast<DatabaseThread*>(vDatabaseThread);
+ return dbThread->databaseThread();
+}
+
+void* DatabaseThread::databaseThread()
+{
+ {
+ // Wait for DatabaseThread::start() to complete.
+ MutexLocker lock(m_threadCreationMutex);
+ LOG(StorageAPI, "Started DatabaseThread %p", this);
+ }
+
+ AutodrainedPool pool;
+ while (OwnPtr<DatabaseTask> task = m_queue.waitForMessage()) {
+ task->performTask();
+ pool.cycle();
+ }
+
+ // Clean up the list of all pending transactions on this database thread
+ m_transactionCoordinator->shutdown();
+
+ LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
+
+ // Close the databases that we ran transactions on. This ensures that if any transactions are still open, they are rolled back and we don't leave the database in an
+ // inconsistent or locked state.
+ if (m_openDatabaseSet.size() > 0) {
+ // As the call to close will modify the original set, we must take a copy to iterate over.
+ DatabaseSet openSetCopy;
+ openSetCopy.swap(m_openDatabaseSet);
+ DatabaseSet::iterator end = openSetCopy.end();
+ for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it)
+ (*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;
+
+ if (cleanupSync) // Someone wanted to know when we were done cleaning up.
+ cleanupSync->taskCompleted();
+
+ return 0;
+}
+
+void DatabaseThread::recordDatabaseOpen(Database* database)
+{
+ ASSERT(currentThread() == m_threadID);
+ ASSERT(database);
+ ASSERT(!m_openDatabaseSet.contains(database));
+ m_openDatabaseSet.add(database);
+}
+
+void DatabaseThread::recordDatabaseClosed(Database* database)
+{
+ ASSERT(currentThread() == m_threadID);
+ ASSERT(database);
+ ASSERT(m_queue.killed() || m_openDatabaseSet.contains(database));
+ m_openDatabaseSet.remove(database);
+}
+
+void DatabaseThread::scheduleTask(PassOwnPtr<DatabaseTask> task)
+{
+ ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination());
+ m_queue.append(task);
+}
+
+void DatabaseThread::scheduleImmediateTask(PassOwnPtr<DatabaseTask> task)
+{
+ ASSERT(!task->hasSynchronizer() || task->hasCheckedForTermination());
+ m_queue.prepend(task);
+}
+
+class SameDatabasePredicate {
+public:
+ SameDatabasePredicate(const Database* database) : m_database(database) { }
+ bool operator()(DatabaseTask* task) const { return task->database() == m_database; }
+private:
+ const Database* m_database;
+};
+
+void DatabaseThread::unscheduleDatabaseTasks(Database* database)
+{
+ // Note that the thread loop is running, so some tasks for the database
+ // may still be executed. This is unavoidable.
+ SameDatabasePredicate predicate(database);
+ m_queue.removeIf(predicate);
+}
+} // namespace WebCore
+#endif
diff --git a/Source/WebCore/storage/DatabaseThread.h b/Source/WebCore/storage/DatabaseThread.h
new file mode 100644
index 0000000..c81e376
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseThread.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 DatabaseThread_h
+#define DatabaseThread_h
+
+#if ENABLE(DATABASE)
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class Database;
+class DatabaseTask;
+class DatabaseTaskSynchronizer;
+class Document;
+class SQLTransactionClient;
+class SQLTransactionCoordinator;
+
+class DatabaseThread : public ThreadSafeShared<DatabaseThread> {
+public:
+ static PassRefPtr<DatabaseThread> create() { return adoptRef(new DatabaseThread); }
+ ~DatabaseThread();
+
+ bool start();
+ void requestTermination(DatabaseTaskSynchronizer* cleanupSync);
+ bool terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer = 0) const;
+
+ void scheduleTask(PassOwnPtr<DatabaseTask>);
+ void scheduleImmediateTask(PassOwnPtr<DatabaseTask>); // This just adds the task to the front of the queue - the caller needs to be extremely careful not to create deadlocks when waiting for completion.
+ void unscheduleDatabaseTasks(Database*);
+
+ void recordDatabaseOpen(Database*);
+ void recordDatabaseClosed(Database*);
+ ThreadIdentifier getThreadID() { return m_threadID; }
+
+ SQLTransactionClient* transactionClient() { return m_transactionClient.get(); }
+ SQLTransactionCoordinator* transactionCoordinator() { return m_transactionCoordinator.get(); }
+
+private:
+ DatabaseThread();
+
+ static void* databaseThreadStart(void*);
+ void* databaseThread();
+
+ Mutex m_threadCreationMutex;
+ ThreadIdentifier m_threadID;
+ RefPtr<DatabaseThread> m_selfRef;
+
+ MessageQueue<DatabaseTask> m_queue;
+
+ // This set keeps track of the open databases that have been used on this thread.
+ typedef HashSet<RefPtr<Database> > DatabaseSet;
+ DatabaseSet m_openDatabaseSet;
+
+ OwnPtr<SQLTransactionClient> m_transactionClient;
+ OwnPtr<SQLTransactionCoordinator> m_transactionCoordinator;
+ DatabaseTaskSynchronizer* m_cleanupSync;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+#endif // DatabaseThread_h
diff --git a/Source/WebCore/storage/DatabaseTracker.cpp b/Source/WebCore/storage/DatabaseTracker.cpp
new file mode 100644
index 0000000..0b47842
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseTracker.cpp
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 "DatabaseTracker.h"
+
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DatabaseThread.h"
+#include "DatabaseTrackerClient.h"
+#include "Logging.h"
+#include "OriginQuotaManager.h"
+#include "Page.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "SecurityOriginHash.h"
+#include "SQLiteFileSystem.h"
+#include "SQLiteStatement.h"
+#include <wtf/MainThread.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+static WebCore::OriginQuotaManager& originQuotaManager()
+{
+ DEFINE_STATIC_LOCAL(WebCore::OriginQuotaManager, quotaManager, ());
+ return quotaManager;
+}
+
+namespace WebCore {
+
+static DatabaseTracker* staticTracker = 0;
+
+void DatabaseTracker::initializeTracker(const String& databasePath)
+{
+ ASSERT(!staticTracker);
+ if (staticTracker)
+ return;
+
+ staticTracker = new DatabaseTracker(databasePath);
+}
+
+DatabaseTracker& DatabaseTracker::tracker()
+{
+ if (!staticTracker)
+ staticTracker = new DatabaseTracker("");
+
+ return *staticTracker;
+}
+
+DatabaseTracker::DatabaseTracker(const String& databasePath)
+ : m_client(0)
+{
+ setDatabaseDirectoryPath(databasePath);
+
+ SQLiteFileSystem::registerSQLiteVFS();
+
+ MutexLocker lockDatabase(m_databaseGuard);
+ populateOrigins();
+}
+
+void DatabaseTracker::setDatabaseDirectoryPath(const String& path)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(!m_database.isOpen());
+ m_databaseDirectoryPath = path.threadsafeCopy();
+}
+
+String DatabaseTracker::databaseDirectoryPath() const
+{
+ return m_databaseDirectoryPath.threadsafeCopy();
+}
+
+String DatabaseTracker::trackerDatabasePath() const
+{
+ return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, "Databases.db");
+}
+
+void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+
+ if (m_database.isOpen())
+ return;
+
+ String databasePath = trackerDatabasePath();
+ if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createIfDoesNotExist))
+ return;
+
+ 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)
+{
+ SecurityOrigin* origin = context->securityOrigin();
+ ProposedDatabase details;
+
+ unsigned long long requirement;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+
+ if (!canCreateDatabase(origin, name))
+ return false;
+
+ recordCreatingDatabase(origin, name);
+
+ // 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 a database already exists, ignore the passed-in estimated size and say it's OK.
+ if (hasEntryForDatabase(origin, name))
+ return true;
+
+ // 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);
+
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ m_proposedDatabases.remove(&details);
+
+ // If the database will fit now, allow its creation.
+ if (requirement <= quotaForOriginNoLock(origin))
+ return true;
+
+ doneCreatingDatabase(origin, name);
+
+ return false;
+}
+
+bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin)
+{
+ 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(!m_databaseGuard.tryLock());
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return false;
+ SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?;");
+
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(2, databaseIdentifier);
+
+ return statement.step() == SQLResultRow;
+}
+
+unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
+{
+ // 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
+ MutexLocker lockDatabase(m_databaseGuard);
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ SecurityOrigin* origin = database->securityOrigin();
+ return quotaForOriginNoLock(origin) - originQuotaManager().diskUsage(origin) + SQLiteFileSystem::getDatabaseFileSize(database->fileName());
+}
+
+void DatabaseTracker::databaseChanged(AbstractDatabase* database)
+{
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().markDatabase(database);
+}
+
+void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
+{
+ Vector<RefPtr<AbstractDatabase> > openDatabases;
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+ if (!m_openDatabaseMap)
+ return;
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin());
+ if (!nameMap)
+ return;
+
+ DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
+ for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
+ DatabaseSet* databaseSet = dbNameMapIt->second;
+ DatabaseSet::const_iterator dbSetEndIt = databaseSet->end();
+ for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) {
+ if ((*dbSetIt)->scriptExecutionContext() == context)
+ openDatabases.append(*dbSetIt);
+ }
+ }
+ }
+
+ Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesEndIt = openDatabases.end();
+ for (Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt)
+ (*openDatabasesIt)->interrupt();
+}
+
+String DatabaseTracker::originPath(SecurityOrigin* origin) const
+{
+ return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.threadsafeCopy(), origin->databaseIdentifier());
+}
+
+String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const String& name, bool createIfNotExists)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ ASSERT(!originQuotaManager().tryLock());
+
+ 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);
+
+ // Make sure the path for this SecurityOrigin exists
+ if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(originPath))
+ return String();
+
+ // See if we have a path for this database yet
+ if (!m_database.isOpen())
+ return String();
+ SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
+
+ if (statement.prepare() != SQLResultOk)
+ return String();
+
+ statement.bindText(1, originIdentifier);
+ statement.bindText(2, name);
+
+ int result = statement.step();
+
+ if (result == SQLResultRow)
+ return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement.getColumnText(0));
+ if (!createIfNotExists)
+ return String();
+
+ if (result != SQLResultDone) {
+ 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, 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);
+ 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;
+
+ m_quotaMap = adoptPtr(new QuotaMap);
+
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return;
+
+ SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins");
+
+ 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()->threadsafeCopy(), statement.getColumnInt64(1));
+ }
+
+ if (result != SQLResultDone)
+ LOG_ERROR("Failed to read in all origins from the database.");
+}
+
+void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(m_quotaMap);
+ copyKeysToVector(*m_quotaMap, result);
+}
+
+bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector)
+{
+ ASSERT(!m_databaseGuard.tryLock());
+ openTrackerDatabase(false);
+ if (!m_database.isOpen())
+ return false;
+
+ SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
+
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+
+ int result;
+ while ((result = statement.step()) == SQLResultRow)
+ resultVector.append(statement.getColumnText(0));
+
+ if (result != SQLResultDone) {
+ LOG_ERROR("Failed to retrieve all database names for origin %s", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
+
+ return true;
+}
+
+bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
+{
+ Vector<String> temp;
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ if (!databaseNamesForOriginNoLock(origin, temp))
+ return false;
+ }
+
+ 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;
+
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ 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;
+ }
+
+ 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();
+ }
+ displayName = statement.getColumnText(0);
+ expectedUsage = statement.getColumnInt64(1);
+ }
+
+ return DatabaseDetails(name, displayName, expectedUsage, usageForDatabase(name, origin));
+}
+
+void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
+{
+ String originIdentifier = origin->databaseIdentifier();
+ int64_t guid = 0;
+
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ openTrackerDatabase(true);
+ if (!m_database.isOpen())
+ return;
+ SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
+ if (statement.prepare() != SQLResultOk)
+ return;
+
+ statement.bindText(1, originIdentifier);
+ statement.bindText(2, name);
+
+ int result = statement.step();
+ if (result == SQLResultRow)
+ guid = statement.getColumnInt64(0);
+ statement.finalize();
+
+ if (guid == 0) {
+ if (result != SQLResultDone)
+ LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.ascii().data(), originIdentifier.ascii().data());
+ else {
+ // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
+ // But since the tracker file is an external resource not under complete control of our code, it's somewhat invalid to make this an ASSERT case
+ // So we'll print an error instead
+ LOG_ERROR("Could not retrieve guid for database %s in origin %s from the tracker database - it is invalid to set database details on a database that doesn't already exist in the tracker",
+ name.ascii().data(), originIdentifier.ascii().data());
+ }
+ return;
+ }
+
+ SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
+ if (updateStatement.prepare() != SQLResultOk)
+ return;
+
+ updateStatement.bindText(1, displayName);
+ updateStatement.bindInt64(2, estimatedSize);
+ updateStatement.bindInt64(3, guid);
+
+ if (updateStatement.step() != SQLResultDone) {
+ LOG_ERROR("Failed to update details for database %s in origin %s", name.ascii().data(), originIdentifier.ascii().data());
+ return;
+ }
+
+ if (m_client)
+ m_client->dispatchDidModifyDatabase(origin, name);
+}
+
+unsigned long long DatabaseTracker::usageForDatabase(const String& name, SecurityOrigin* origin)
+{
+ String path = fullPathForDatabase(origin, name, false);
+ if (path.isEmpty())
+ return 0;
+
+ return SQLiteFileSystem::getDatabaseFileSize(path);
+}
+
+void DatabaseTracker::addOpenDatabase(AbstractDatabase* database)
+{
+ if (!database)
+ return;
+
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+ if (!m_openDatabaseMap)
+ m_openDatabaseMap = adoptPtr(new DatabaseOriginMap);
+
+ 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.threadsafeCopy(), databaseSet);
+ }
+
+ databaseSet->add(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(AbstractDatabase* database)
+{
+ if (!database)
+ return;
+
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+ if (!m_openDatabaseMap) {
+ 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->remove(database);
+
+ LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
+
+ if (!databaseSet->isEmpty())
+ return;
+
+ nameMap->remove(name);
+ delete databaseSet;
+
+ if (!nameMap->isEmpty())
+ return;
+
+ 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<AbstractDatabase> >* databases)
+{
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ if (!m_openDatabaseMap)
+ return;
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
+ if (!nameMap)
+ return;
+
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet)
+ return;
+
+ for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
+ databases->add(*it);
+}
+
+unsigned long long DatabaseTracker::usageForOriginNoLock(SecurityOrigin* origin)
+{
+ ASSERT(!originQuotaManager().tryLock());
+
+ // Use the OriginQuotaManager mechanism to calculate the usage
+ if (originQuotaManager().tracksOrigin(origin))
+ return originQuotaManager().diskUsage(origin);
+
+ // If the OriginQuotaManager doesn't track this origin already, prime it to do so
+ originQuotaManager().trackOrigin(origin);
+
+ Vector<String> names;
+ databaseNamesForOriginNoLock(origin, names);
+
+ for (unsigned i = 0; i < names.size(); ++i)
+ originQuotaManager().addDatabase(origin, names[i], fullPathForDatabaseNoLock(origin, names[i], false));
+
+ if (!originQuotaManager().tracksOrigin(origin))
+ return 0;
+ return originQuotaManager().diskUsage(origin);
+}
+
+unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
+{
+ 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)
+{
+ MutexLocker lockDatabase(m_databaseGuard);
+
+ if (quotaForOriginNoLock(origin) == quota)
+ return;
+
+ openTrackerDatabase(true);
+ if (!m_database.isOpen())
+ return;
+
+ 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());
+ }
+ } 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();
+ }
+
+ if (error)
+#if OS(WINDOWS)
+ LOG_ERROR("Failed to set quota %I64u in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
+#else
+ LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
+#endif
+ }
+
+ // 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(!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(hasEntryForOriginNoLock(origin));
+
+ SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
+
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(2, name);
+ statement.bindText(3, path);
+
+ if (!statement.executeCommand()) {
+ LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg());
+ return false;
+ }
+
+ if (m_client)
+ m_client->dispatchDidModifyOrigin(origin);
+
+ return true;
+}
+
+void DatabaseTracker::deleteAllDatabases()
+{
+ Vector<RefPtr<SecurityOrigin> > originsCopy;
+ origins(originsCopy);
+
+ for (unsigned i = 0; i < originsCopy.size(); ++i)
+ deleteOrigin(originsCopy[i].get());
+}
+
+// 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)
+{
+ Vector<String> databaseNames;
+ {
+ 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.
+ LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data());
+ }
+ }
+
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ doneDeletingOrigin(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 false;
+ }
+
+ statement.bindText(1, origin->databaseIdentifier());
+
+ if (!statement.executeCommand()) {
+ LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
+ return false;
+ }
+
+ 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;
+ }
+
+ 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));
+
+ RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
+ m_quotaMap->remove(origin);
+
+ {
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().removeOrigin(origin);
+ }
+
+ // If we removed the last origin, do some additional deletion.
+ if (m_quotaMap->isEmpty()) {
+ if (m_database.isOpen())
+ m_database.close();
+ 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;
+}
+
+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::doneCreatingDatabase(SecurityOrigin *origin, const String& name)
+{
+ 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());
+ 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());
+ doneDeletingDatabase(origin, name);
+ return false;
+ }
+
+ statement.bindText(1, origin->databaseIdentifier());
+ statement.bindText(2, 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());
+ doneDeletingDatabase(origin, name);
+ return false;
+ }
+
+ {
+ Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
+ originQuotaManager().removeDatabase(origin, name);
+ }
+
+ if (m_client) {
+ 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)
+{
+ String fullPath = fullPathForDatabase(origin, name, false);
+ if (fullPath.isEmpty())
+ return true;
+
+#ifndef NDEBUG
+ {
+ MutexLocker lockDatabase(m_databaseGuard);
+ ASSERT(deletingDatabase(origin, name) || deletingOrigin(origin));
+ }
+#endif
+
+ Vector<RefPtr<AbstractDatabase> > deletedDatabases;
+
+ // 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, let's check
+ // if they are this database by name.
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (databaseSet && databaseSet->size()) {
+ // We have some database open with this name. Mark them as deleted.
+ DatabaseSet::const_iterator end = databaseSet->end();
+ for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it)
+ deletedDatabases.append(*it);
+ }
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < deletedDatabases.size(); ++i)
+ deletedDatabases[i]->markAsDeletedAndClose();
+
+ return SQLiteFileSystem::deleteDatabaseFile(fullPath);
+}
+
+void DatabaseTracker::setClient(DatabaseTrackerClient* client)
+{
+ m_client = client;
+}
+
+static Mutex& notificationMutex()
+{
+ DEFINE_STATIC_LOCAL(Mutex, mutex, ());
+ return mutex;
+}
+
+typedef Vector<pair<RefPtr<SecurityOrigin>, String> > NotificationQueue;
+
+static NotificationQueue& notificationQueue()
+{
+ DEFINE_STATIC_LOCAL(NotificationQueue, queue, ());
+ return queue;
+}
+
+void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, const String& name)
+{
+ MutexLocker locker(notificationMutex());
+
+ notificationQueue().append(pair<RefPtr<SecurityOrigin>, String>(origin->threadsafeCopy(), name.crossThreadString()));
+ scheduleForNotification();
+}
+
+static bool notificationScheduled = false;
+
+void DatabaseTracker::scheduleForNotification()
+{
+ ASSERT(!notificationMutex().tryLock());
+
+ if (!notificationScheduled) {
+ callOnMainThread(DatabaseTracker::notifyDatabasesChanged, 0);
+ notificationScheduled = true;
+ }
+}
+
+void DatabaseTracker::notifyDatabasesChanged(void*)
+{
+ // Note that if DatabaseTracker ever becomes non-singleton, we'll have to amend this notification
+ // mechanism to include which tracker the notification goes out on as well.
+ DatabaseTracker& theTracker(tracker());
+
+ NotificationQueue notifications;
+ {
+ MutexLocker locker(notificationMutex());
+
+ notifications.swap(notificationQueue());
+
+ notificationScheduled = false;
+ }
+
+ if (!theTracker.m_client)
+ return;
+
+ for (unsigned i = 0; i < notifications.size(); ++i)
+ theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first.get(), notifications[i].second);
+}
+
+
+} // namespace WebCore
+#endif
diff --git a/Source/WebCore/storage/DatabaseTracker.h b/Source/WebCore/storage/DatabaseTracker.h
new file mode 100644
index 0000000..7145e6b
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseTracker.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 DatabaseTracker_h
+#define DatabaseTracker_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+
+#if !PLATFORM(CHROMIUM)
+#include "DatabaseDetails.h"
+#include "SQLiteDatabase.h"
+#include <wtf/OwnPtr.h>
+#endif // !PLATFORM(CHROMIUM)
+
+namespace WebCore {
+
+class AbstractDatabase;
+class ScriptExecutionContext;
+class SecurityOrigin;
+
+struct SecurityOriginHash;
+
+#if !PLATFORM(CHROMIUM)
+class DatabaseTrackerClient;
+
+struct SecurityOriginTraits;
+#endif // !PLATFORM(CHROMIUM)
+
+class DatabaseTracker : public Noncopyable {
+public:
+ static void initializeTracker(const String& databasePath);
+ static DatabaseTracker& tracker();
+ // 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(AbstractDatabase*);
+ void removeOpenDatabase(AbstractDatabase*);
+ void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases);
+
+ unsigned long long getMaxSizeForDatabase(const AbstractDatabase*);
+ void databaseChanged(AbstractDatabase*);
+
+ void interruptAllDatabasesForContext(const ScriptExecutionContext*);
+
+private:
+ DatabaseTracker(const String& databasePath);
+
+ typedef HashSet<AbstractDatabase*> DatabaseSet;
+ typedef HashMap<String, DatabaseSet*> DatabaseNameMap;
+ typedef HashMap<RefPtr<SecurityOrigin>, DatabaseNameMap*, SecurityOriginHash> DatabaseOriginMap;
+
+ Mutex m_openDatabaseMapGuard;
+ mutable OwnPtr<DatabaseOriginMap> m_openDatabaseMap;
+
+#if !PLATFORM(CHROMIUM)
+public:
+ void setDatabaseDirectoryPath(const String&);
+ String databaseDirectoryPath() const;
+
+ void origins(Vector<RefPtr<SecurityOrigin> >& result);
+ bool databaseNamesForOrigin(SecurityOrigin*, Vector<String>& result);
+
+ DatabaseDetails detailsForNameAndOrigin(const String&, SecurityOrigin*);
+
+ unsigned long long usageForDatabase(const String&, SecurityOrigin*);
+ unsigned long long usageForOrigin(SecurityOrigin*);
+ unsigned long long quotaForOrigin(SecurityOrigin*);
+ void setQuota(SecurityOrigin*, unsigned long long);
+
+ void deleteAllDatabases();
+ 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);
+
+ 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);
+
+ String originPath(SecurityOrigin*) const;
+
+ bool hasEntryForDatabase(SecurityOrigin*, const String& databaseIdentifier);
+
+ bool addDatabase(SecurityOrigin*, const String& name, const String& path);
+ void populateOrigins();
+
+ 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;
+ mutable OwnPtr<QuotaMap> m_quotaMap;
+
+ String m_databaseDirectoryPath;
+
+ DatabaseTrackerClient* m_client;
+
+ 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*);
+#endif // !PLATFORM(CHROMIUM)
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+#endif // DatabaseTracker_h
diff --git a/Source/WebCore/storage/DatabaseTrackerClient.h b/Source/WebCore/storage/DatabaseTrackerClient.h
new file mode 100644
index 0000000..2e0497f
--- /dev/null
+++ b/Source/WebCore/storage/DatabaseTrackerClient.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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 DatabaseTrackerClient_h
+#define DatabaseTrackerClient_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class SecurityOrigin;
+
+class DatabaseTrackerClient {
+public:
+ virtual ~DatabaseTrackerClient() { }
+ virtual void dispatchDidModifyOrigin(SecurityOrigin*) = 0;
+ virtual void dispatchDidModifyDatabase(SecurityOrigin*, const String& databaseName) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // DatabaseTrackerClient_h
diff --git a/Source/WebCore/storage/IDBAbortEvent.cpp b/Source/WebCore/storage/IDBAbortEvent.cpp
new file mode 100644
index 0000000..21760f8
--- /dev/null
+++ b/Source/WebCore/storage/IDBAbortEvent.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 "IDBAbortEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBAbortEvent> IDBAbortEvent::create()
+{
+ return adoptRef(new IDBAbortEvent());
+}
+
+IDBAbortEvent::IDBAbortEvent()
+ : IDBEvent(eventNames().abortEvent, 0) // FIXME: set the source to the transaction
+{
+}
+
+IDBAbortEvent::~IDBAbortEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBAbortEvent.h b/Source/WebCore/storage/IDBAbortEvent.h
new file mode 100644
index 0000000..bdc2202
--- /dev/null
+++ b/Source/WebCore/storage/IDBAbortEvent.h
@@ -0,0 +1,57 @@
+/*
+ * 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 IDBAbortEvent_h
+#define IDBAbortEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBAbortEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBAbortEvent> create();
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBAbortEvent();
+
+ virtual bool isIDBAbortEvent() const { return true; }
+
+private:
+ IDBAbortEvent();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBAbortEvent_h
diff --git a/Source/WebCore/storage/IDBAny.cpp b/Source/WebCore/storage/IDBAny.cpp
new file mode 100644
index 0000000..3a049c0
--- /dev/null
+++ b/Source/WebCore/storage/IDBAny.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "IDBCursor.h"
+#include "IDBDatabase.h"
+#include "IDBFactory.h"
+#include "IDBIndex.h"
+#include "IDBObjectStore.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBAny> IDBAny::createInvalid()
+{
+ return adoptRef(new IDBAny());
+}
+
+PassRefPtr<IDBAny> IDBAny::createNull()
+{
+ RefPtr<IDBAny> idbAny = adoptRef(new IDBAny());
+ idbAny->setNull();
+ return idbAny.release();
+}
+
+IDBAny::IDBAny()
+ : m_type(UndefinedType)
+{
+}
+
+IDBAny::~IDBAny()
+{
+}
+
+PassRefPtr<IDBCursor> IDBAny::idbCursor()
+{
+ ASSERT(m_type == IDBCursorType);
+ return m_idbCursor;
+}
+
+PassRefPtr<IDBDatabase> IDBAny::idbDatabase()
+{
+ ASSERT(m_type == IDBDatabaseType);
+ return m_idbDatabase;
+}
+
+PassRefPtr<IDBFactory> IDBAny::idbFactory()
+{
+ ASSERT(m_type == IDBFactoryType);
+ return m_idbFactory;
+}
+
+PassRefPtr<IDBIndex> IDBAny::idbIndex()
+{
+ ASSERT(m_type == IDBIndexType);
+ return m_idbIndex;
+}
+
+PassRefPtr<IDBKey> IDBAny::idbKey()
+{
+ ASSERT(m_type == IDBKeyType);
+ return m_idbKey;
+}
+
+PassRefPtr<IDBObjectStore> IDBAny::idbObjectStore()
+{
+ ASSERT(m_type == IDBObjectStoreType);
+ return m_idbObjectStore;
+}
+
+PassRefPtr<IDBTransaction> IDBAny::idbTransaction()
+{
+ ASSERT(m_type == IDBTransactionType);
+ return m_idbTransaction;
+}
+
+PassRefPtr<SerializedScriptValue> IDBAny::serializedScriptValue()
+{
+ ASSERT(m_type == SerializedScriptValueType);
+ return m_serializedScriptValue;
+}
+
+void IDBAny::setNull()
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = NullType;
+}
+
+void IDBAny::set(PassRefPtr<IDBCursor> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBCursorType;
+ m_idbCursor = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBDatabase> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBDatabaseType;
+ m_idbDatabase = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBFactory> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBFactoryType;
+ m_idbFactory = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBIndex> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBIndexType;
+ m_idbIndex = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBKey> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBKeyType;
+ m_idbKey = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBTransaction> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBTransactionType;
+ m_idbTransaction = value;
+}
+
+void IDBAny::set(PassRefPtr<IDBObjectStore> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBObjectStoreType;
+ m_idbObjectStore = value;
+}
+
+void IDBAny::set(PassRefPtr<SerializedScriptValue> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = SerializedScriptValueType;
+ m_serializedScriptValue = value;
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBAny.h b/Source/WebCore/storage/IDBAny.h
new file mode 100644
index 0000000..8e3f83e
--- /dev/null
+++ b/Source/WebCore/storage/IDBAny.h
@@ -0,0 +1,121 @@
+/*
+ * 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 IDBCursor;
+class IDBDatabase;
+class IDBFactory;
+class IDBIndex;
+class IDBKey;
+class IDBObjectStore;
+class IDBTransaction;
+class SerializedScriptValue;
+
+class IDBAny : public RefCounted<IDBAny> {
+public:
+ static PassRefPtr<IDBAny> createInvalid();
+ static PassRefPtr<IDBAny> createNull();
+ template<typename T>
+ static PassRefPtr<IDBAny> create(T* idbObject)
+ {
+ RefPtr<IDBAny> any = IDBAny::createInvalid();
+ any->set(idbObject);
+ return any.release();
+ }
+ template<typename T>
+ static PassRefPtr<IDBAny> create(PassRefPtr<T> idbObject)
+ {
+ RefPtr<IDBAny> any = IDBAny::createInvalid();
+ any->set(idbObject);
+ return any.release();
+ }
+ ~IDBAny();
+
+ enum Type {
+ UndefinedType = 0,
+ NullType,
+ IDBCursorType,
+ IDBDatabaseType,
+ IDBFactoryType,
+ IDBIndexType,
+ IDBKeyType,
+ IDBObjectStoreType,
+ IDBTransactionType,
+ SerializedScriptValueType
+ };
+
+ Type type() const { return m_type; }
+ // Use type() to figure out which one of these you're allowed to call.
+ PassRefPtr<IDBCursor> idbCursor();
+ PassRefPtr<IDBDatabase> idbDatabase();
+ PassRefPtr<IDBFactory> idbFactory();
+ PassRefPtr<IDBIndex> idbIndex();
+ PassRefPtr<IDBKey> idbKey();
+ PassRefPtr<IDBObjectStore> idbObjectStore();
+ PassRefPtr<IDBTransaction> idbTransaction();
+ PassRefPtr<SerializedScriptValue> serializedScriptValue();
+
+ // Set can only be called once.
+ void setNull();
+ void set(PassRefPtr<IDBCursor>);
+ void set(PassRefPtr<IDBDatabase>);
+ void set(PassRefPtr<IDBFactory>);
+ void set(PassRefPtr<IDBIndex>);
+ void set(PassRefPtr<IDBKey>);
+ void set(PassRefPtr<IDBObjectStore>);
+ void set(PassRefPtr<IDBTransaction>);
+ void set(PassRefPtr<SerializedScriptValue>);
+
+private:
+ IDBAny();
+
+ Type m_type;
+
+ // Only one of the following should ever be in use at any given time.
+ RefPtr<IDBCursor> m_idbCursor;
+ RefPtr<IDBDatabase> m_idbDatabase;
+ RefPtr<IDBFactory> m_idbFactory;
+ RefPtr<IDBIndex> m_idbIndex;
+ RefPtr<IDBKey> m_idbKey;
+ RefPtr<IDBObjectStore> m_idbObjectStore;
+ RefPtr<IDBTransaction> m_idbTransaction;
+ RefPtr<SerializedScriptValue> m_serializedScriptValue;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBAny_h
diff --git a/Source/WebCore/storage/IDBAny.idl b/Source/WebCore/storage/IDBAny.idl
new file mode 100644
index 0000000..19d8424
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBCallbacks.h b/Source/WebCore/storage/IDBCallbacks.h
new file mode 100644
index 0000000..e62c085
--- /dev/null
+++ b/Source/WebCore/storage/IDBCallbacks.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 IDBCallbacks_h
+#define IDBCallbacks_h
+
+#include "IDBCursorBackendInterface.h"
+#include "IDBDatabaseBackendInterface.h"
+#include "IDBDatabaseError.h"
+#include "IDBIndexBackendInterface.h"
+#include "IDBKey.h"
+#include "IDBObjectStoreBackendInterface.h"
+#include "IDBTransactionBackendInterface.h"
+#include "SerializedScriptValue.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+// FIXME: All child classes need to be made threadsafe.
+class IDBCallbacks : public ThreadSafeShared<IDBCallbacks> {
+public:
+ virtual ~IDBCallbacks() { }
+
+ virtual void onError(PassRefPtr<IDBDatabaseError>) = 0;
+ virtual void onSuccess() = 0; // For "null".
+ virtual void onSuccess(PassRefPtr<IDBCursorBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBDatabaseBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBKey>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBObjectStoreBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<SerializedScriptValue>) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBCallbacks_h
diff --git a/Source/WebCore/storage/IDBCompleteEvent.cpp b/Source/WebCore/storage/IDBCompleteEvent.cpp
new file mode 100644
index 0000000..f0ad9fc
--- /dev/null
+++ b/Source/WebCore/storage/IDBCompleteEvent.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 "IDBCompleteEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBCompleteEvent> IDBCompleteEvent::create()
+{
+ return adoptRef(new IDBCompleteEvent());
+}
+
+IDBCompleteEvent::IDBCompleteEvent()
+ : IDBEvent(eventNames().completeEvent, 0) // FIXME: set the source to the transaction
+{
+}
+
+IDBCompleteEvent::~IDBCompleteEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBCompleteEvent.h b/Source/WebCore/storage/IDBCompleteEvent.h
new file mode 100644
index 0000000..c407096
--- /dev/null
+++ b/Source/WebCore/storage/IDBCompleteEvent.h
@@ -0,0 +1,57 @@
+/*
+ * 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 IDBCompleteEvent_h
+#define IDBCompleteEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBCompleteEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBCompleteEvent> create();
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBCompleteEvent();
+
+ virtual bool isIDBCompleteEvent() const { return true; }
+
+private:
+ IDBCompleteEvent();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBCompleteEvent_h
diff --git a/Source/WebCore/storage/IDBCursor.cpp b/Source/WebCore/storage/IDBCursor.cpp
new file mode 100644
index 0000000..444c109
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursor.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "IDBCursor.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBAny.h"
+#include "IDBCallbacks.h"
+#include "IDBCursorBackendInterface.h"
+#include "IDBKey.h"
+#include "IDBRequest.h"
+#include "IDBTransactionBackendInterface.h"
+#include "ScriptExecutionContext.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBCursor::IDBCursor(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBTransactionBackendInterface* transaction)
+ : m_backend(backend)
+ , m_request(request)
+ , m_transaction(transaction)
+{
+ ASSERT(m_backend);
+ ASSERT(m_request);
+ ASSERT(m_transaction);
+}
+
+IDBCursor::~IDBCursor()
+{
+}
+
+unsigned short IDBCursor::direction() const
+{
+ return m_backend->direction();
+}
+
+PassRefPtr<IDBKey> IDBCursor::key() const
+{
+ return m_backend->key();
+}
+
+PassRefPtr<IDBAny> IDBCursor::value() const
+{
+ return m_backend->value();
+}
+
+PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->update(value, request, ec);
+ if (ec)
+ return 0;
+ return request.release();
+}
+
+void IDBCursor::continueFunction(PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ // FIXME: We're not using the context from when continue was called, which means the callback
+ // will be on the original context openCursor was called on. Is this right?
+ if (m_request->resetReadyState(m_transaction.get()))
+ m_backend->continueFunction(key, m_request, ec);
+ else
+ ASSERT_NOT_REACHED();
+}
+
+PassRefPtr<IDBRequest> IDBCursor::deleteFunction(ScriptExecutionContext* context, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->deleteFunction(request, ec);
+ if (ec)
+ return 0;
+ return request.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBCursor.h b/Source/WebCore/storage/IDBCursor.h
new file mode 100644
index 0000000..54bf51a
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursor.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:
+ *
+ * 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 IDBCursor_h
+#define IDBCursor_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ExceptionCode.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBAny;
+class IDBCallbacks;
+class IDBCursorBackendInterface;
+class IDBKey;
+class IDBRequest;
+class ScriptExecutionContext;
+class SerializedScriptValue;
+class IDBTransactionBackendInterface;
+
+class IDBCursor : public RefCounted<IDBCursor> {
+public:
+ enum Direction {
+ NEXT = 0,
+ NEXT_NO_DUPLICATE = 1,
+ PREV = 2,
+ PREV_NO_DUPLICATE = 3,
+ };
+ static PassRefPtr<IDBCursor> create(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBTransactionBackendInterface* transaction)
+ {
+ return adoptRef(new IDBCursor(backend, request, transaction));
+ }
+ ~IDBCursor();
+
+ // FIXME: Try to modify the code generator so this is unneeded.
+ void continueFunction(ExceptionCode& ec) { continueFunction(0, ec); }
+
+ // Implement the IDL
+ unsigned short direction() const;
+ PassRefPtr<IDBKey> key() const;
+ PassRefPtr<IDBAny> value() const;
+ PassRefPtr<IDBRequest> update(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, ExceptionCode&);
+ void continueFunction(PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> deleteFunction(ScriptExecutionContext*, ExceptionCode&);
+
+private:
+ explicit IDBCursor(PassRefPtr<IDBCursorBackendInterface>, IDBRequest*, IDBTransactionBackendInterface*);
+
+ RefPtr<IDBCursorBackendInterface> m_backend;
+ RefPtr<IDBRequest> m_request;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBCursor_h
diff --git a/Source/WebCore/storage/IDBCursor.idl b/Source/WebCore/storage/IDBCursor.idl
new file mode 100644
index 0000000..12d0baf
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursor.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
+ ] IDBCursor {
+ const unsigned short NEXT = 0;
+ const unsigned short NEXT_NO_DUPLICATE = 1;
+ const unsigned short PREV = 2;
+ const unsigned short PREV_NO_DUPLICATE = 3;
+
+ readonly attribute unsigned short direction;
+ readonly attribute IDBKey key;
+ readonly attribute IDBAny value;
+
+ // FIXME: Implement.
+ //[CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value)
+ // raises (IDBDatabaseException);
+ [ImplementationFunction=continueFunction] void continue(in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext, ImplementationFunction=deleteFunction] IDBRequest delete()
+ raises (IDBDatabaseException);
+ };
+}
diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.cpp b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
new file mode 100644
index 0000000..9b4e4f1
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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 "IDBCursorBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
+#include "IDBCallbacks.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseError.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndexBackendImpl.h"
+#include "IDBKeyRange.h"
+#include "IDBObjectStoreBackendImpl.h"
+#include "IDBRequest.h"
+#include "IDBSQLiteDatabase.h"
+#include "IDBTransactionBackendInterface.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBCursorBackendImpl::IDBCursorBackendImpl(IDBSQLiteDatabase* database, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
+ : m_database(database)
+ , m_keyRange(keyRange)
+ , m_direction(direction)
+ , m_query(query)
+ , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
+ , m_transaction(transaction)
+ , m_objectStore(objectStore)
+{
+ loadCurrentRow();
+}
+
+IDBCursorBackendImpl::~IDBCursorBackendImpl()
+{
+}
+
+unsigned short IDBCursorBackendImpl::direction() const
+{
+ return m_direction;
+}
+
+PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
+{
+
+ return m_currentKey;
+}
+
+PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
+{
+ if (m_isSerializedScriptValueCursor)
+ return IDBAny::create(m_currentSerializedScriptValue.get());
+ return IDBAny::create(m_currentIDBKeyValue.get());
+}
+
+void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = this;
+ RefPtr<SerializedScriptValue> value = prpValue;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ // FIXME: Throw DATA_ERR and SERIAL_ERR when appropriate.
+ if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::updateInternal, cursor, value, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBCursorBackendImpl::updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
+{
+ // FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
+ return;
+
+ RefPtr<SerializedScriptValue> value = prpValue;
+
+ if (!cursor->m_query || cursor->m_currentId == InvalidId) {
+ // FIXME: Use the proper error code when it's specced.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
+ return;
+ }
+
+ String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?";
+ SQLiteStatement updateQuery(cursor->database(), sql);
+
+ bool ok = updateQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ updateQuery.bindText(1, value->toWireString());
+ updateQuery.bindInt64(2, cursor->m_currentId);
+ ok = updateQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+
+ if (cursor->m_isSerializedScriptValueCursor)
+ cursor->m_currentSerializedScriptValue = value.release();
+ callbacks->onSuccess();
+}
+
+void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, cursor, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
+ RefPtr<IDBKey> key = prpKey;
+ while (true) {
+ if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
+ cursor->m_query = 0;
+ cursor->m_currentId = InvalidId;
+ cursor->m_currentKey = 0;
+ cursor->m_currentSerializedScriptValue = 0;
+ cursor->m_currentIDBKeyValue = 0;
+ callbacks->onSuccess();
+ return;
+ }
+
+ RefPtr<IDBKey> oldKey = cursor->m_currentKey;
+ cursor->loadCurrentRow();
+
+ // If a key was supplied, we must loop until we find that key (or hit the end).
+ if (key && !key->isEqual(cursor->m_currentKey.get()))
+ continue;
+
+ // If we don't have a uniqueness constraint, we can stop now.
+ if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
+ break;
+ if (!cursor->m_currentKey->isEqual(oldKey.get()))
+ break;
+ }
+
+ callbacks->onSuccess(cursor.get());
+}
+
+void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+
+ // FIXME: Check that the transaction is READ_WRITE
+ // if (m_transaction->mode() == IDBTransaction::READ_ONLY) {
+ // FIXME: We must return READ_ONLY_ERR here. Fix this when we update IDBDatabaseException to match the spec.
+ // ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ // return;
+ // }
+ RefPtr<IDBKey> key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey;
+ m_objectStore->deleteFunction(key.release(), prpCallbacks, m_transaction.get(), ec);
+}
+
+
+void IDBCursorBackendImpl::loadCurrentRow()
+{
+ // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal or
+ // IDBIndexBackendImpl::openCursorInternal.
+ m_currentId = m_query->getColumnInt64(0);
+ m_currentKey = IDBKey::fromQuery(*m_query, 1);
+ if (m_isSerializedScriptValueCursor)
+ m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
+
+ m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 5);
+}
+
+SQLiteDatabase& IDBCursorBackendImpl::database() const
+{
+ return m_database->db();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.h b/Source/WebCore/storage/IDBCursorBackendImpl.h
new file mode 100644
index 0000000..e3a8995
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursorBackendImpl.h
@@ -0,0 +1,98 @@
+/*
+ * 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 IDBCursorBackendImpl_h
+#define IDBCursorBackendImpl_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCursor.h"
+#include "IDBCursorBackendInterface.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBDatabaseBackendImpl;
+class IDBIndexBackendImpl;
+class IDBKeyRange;
+class IDBObjectStoreBackendInterface;
+class IDBSQLiteDatabase;
+class IDBTransactionBackendInterface;
+class SQLiteDatabase;
+class SQLiteStatement;
+class SerializedScriptValue;
+
+class IDBCursorBackendImpl : public IDBCursorBackendInterface {
+public:
+ static PassRefPtr<IDBCursorBackendImpl> create(IDBSQLiteDatabase* database, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
+ {
+ return adoptRef(new IDBCursorBackendImpl(database, keyRange, direction, query, isSerializedScriptValueCursor, transaction, objectStore));
+ }
+ virtual ~IDBCursorBackendImpl();
+
+ virtual unsigned short direction() const;
+ virtual PassRefPtr<IDBKey> key() const;
+ virtual PassRefPtr<IDBAny> value() const;
+ virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual void deleteFunction(PassRefPtr<IDBCallbacks>, ExceptionCode&);
+
+private:
+ IDBCursorBackendImpl(IDBSQLiteDatabase*, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*);
+
+ void loadCurrentRow();
+ SQLiteDatabase& database() const;
+
+ static void updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>);
+ static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+
+ static const int64_t InvalidId = -1;
+
+ RefPtr<IDBSQLiteDatabase> m_database;
+
+ RefPtr<IDBKeyRange> m_keyRange;
+ IDBCursor::Direction m_direction;
+ OwnPtr<SQLiteStatement> m_query;
+ bool m_isSerializedScriptValueCursor;
+ int64_t m_currentId;
+ RefPtr<IDBKey> m_currentKey;
+
+ // m_isSerializedScriptValueCursor will only be available for object cursors.
+ RefPtr<SerializedScriptValue> m_currentSerializedScriptValue;
+ // FIXME: make the primary key available via script for all types of cursors.
+ RefPtr<IDBKey> m_currentIDBKeyValue;
+
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
+ RefPtr<IDBObjectStoreBackendInterface> m_objectStore;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBCursorBackendImpl_h
diff --git a/Source/WebCore/storage/IDBCursorBackendInterface.h b/Source/WebCore/storage/IDBCursorBackendInterface.h
new file mode 100644
index 0000000..0d132ca
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursorBackendInterface.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.
+ *
+ * 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 IDBCursorBackendInterface_h
+#define IDBCursorBackendInterface_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ExceptionCode.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class IDBAny;
+class IDBCallbacks;
+class IDBKey;
+class IDBRequest;
+class SerializedScriptValue;
+
+class IDBCursorBackendInterface : public ThreadSafeShared<IDBCursorBackendInterface> {
+public:
+ virtual ~IDBCursorBackendInterface() {}
+
+ virtual unsigned short direction() const = 0;
+ virtual PassRefPtr<IDBKey> key() const = 0;
+ virtual PassRefPtr<IDBAny> value() const = 0;
+
+ virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual void deleteFunction(PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBCursorBackendInterface_h
diff --git a/Source/WebCore/storage/IDBDatabase.cpp b/Source/WebCore/storage/IDBDatabase.cpp
new file mode 100644
index 0000000..7a9141a
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabase.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "IDBDatabase.h"
+
+#include "IDBAny.h"
+#include "IDBDatabaseError.h"
+#include "IDBDatabaseException.h"
+#include "IDBFactoryBackendInterface.h"
+#include "IDBIndex.h"
+#include "IDBObjectStore.h"
+#include "IDBRequest.h"
+#include "IDBTransaction.h"
+#include "ScriptExecutionContext.h"
+#include <limits>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+// FIXME: We need to spec this differently.
+const unsigned long defaultTimeout = 0; // Infinite.
+
+IDBDatabase::IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface> backend)
+ : m_backend(backend)
+{
+ // We pass a reference of this object before it can be adopted.
+ relaxAdoptionRequirement();
+}
+
+IDBDatabase::~IDBDatabase()
+{
+}
+
+void IDBDatabase::setSetVersionTransaction(IDBTransactionBackendInterface* transaction)
+{
+ m_setVersionTransaction = transaction;
+}
+
+PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const OptionsObject& options, ExceptionCode& ec)
+{
+ if (!m_setVersionTransaction) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ String keyPath;
+ options.getKeyString("keyPath", keyPath);
+ bool autoIncrement = false;
+ options.getKeyBool("autoIncrement", autoIncrement);
+ // FIXME: Look up evictable and pass that on as well.
+
+ if (autoIncrement) {
+ // FIXME: Implement support for auto increment.
+ ec = IDBDatabaseException::UNKNOWN_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBObjectStoreBackendInterface> objectStore = m_backend->createObjectStore(name, keyPath, autoIncrement, m_setVersionTransaction.get(), ec);
+ if (!objectStore) {
+ ASSERT(ec);
+ return 0;
+ }
+ return IDBObjectStore::create(objectStore.release(), m_setVersionTransaction.get());
+}
+
+void IDBDatabase::deleteObjectStore(const String& name, ExceptionCode& ec)
+{
+ if (!m_setVersionTransaction) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+
+ m_backend->deleteObjectStore(name, m_setVersionTransaction.get(), ec);
+}
+
+PassRefPtr<IDBRequest> IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), 0);
+ m_backend->setVersion(version, request, ec);
+ return request;
+}
+
+PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* context, const OptionsObject& options, ExceptionCode& ec)
+{
+ RefPtr<DOMStringList> storeNames = options.getKeyDOMStringList("objectStoreNames");
+ if (!storeNames) {
+ storeNames = DOMStringList::create();
+ String storeName;
+ if (options.getKeyString("objectStoreNames", storeName))
+ storeNames->append(storeName);
+ }
+
+ // Gets cast to an unsigned short.
+ int32_t mode = IDBTransaction::READ_ONLY;
+ options.getKeyInt32("mode", mode);
+ if (mode != IDBTransaction::READ_WRITE && mode != IDBTransaction::READ_ONLY) {
+ // FIXME: May need to change when specced: http://www.w3.org/Bugs/Public/show_bug.cgi?id=11406
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+
+ // Gets cast to an unsigned long.
+ // FIXME: The spec needs to be updated on this. It should probably take a double.
+ int32_t timeout = defaultTimeout;
+ options.getKeyInt32("timeout", timeout);
+ int64_t unsignedLongMax = std::numeric_limits<unsigned long>::max();
+ if (timeout < 0 || timeout > unsignedLongMax)
+ timeout = defaultTimeout; // Ignore illegal values.
+
+ // We need to create a new transaction synchronously. Locks are acquired asynchronously. Operations
+ // can be queued against the transaction at any point. They will start executing as soon as the
+ // appropriate locks have been acquired.
+ // Also note that each backend object corresponds to exactly one IDBTransaction object.
+ RefPtr<IDBTransactionBackendInterface> transactionBackend = m_backend->transaction(storeNames.get(), mode, timeout, ec);
+ if (!transactionBackend) {
+ ASSERT(ec);
+ return 0;
+ }
+ RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend, this);
+ transactionBackend->setCallbacks(transaction.get());
+ return transaction.release();
+}
+
+void IDBDatabase::close()
+{
+ m_backend->close();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBDatabase.h b/Source/WebCore/storage/IDBDatabase.h
new file mode 100644
index 0000000..9ebbf00
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabase.h
@@ -0,0 +1,83 @@
+/*
+ * 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 "DOMStringList.h"
+#include "ExceptionCode.h"
+#include "IDBDatabaseBackendInterface.h"
+#include "IDBObjectStore.h"
+#include "IDBTransaction.h"
+#include "OptionsObject.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBAny;
+class IDBRequest;
+class ScriptExecutionContext;
+
+class IDBDatabase : public RefCounted<IDBDatabase> {
+public:
+ static PassRefPtr<IDBDatabase> create(PassRefPtr<IDBDatabaseBackendInterface> database)
+ {
+ return adoptRef(new IDBDatabase(database));
+ }
+ ~IDBDatabase();
+
+ void setSetVersionTransaction(IDBTransactionBackendInterface*);
+
+ // Implement the IDL
+ String name() const { return m_backend->name(); }
+ String version() const { return m_backend->version(); }
+ PassRefPtr<DOMStringList> objectStoreNames() const { return m_backend->objectStoreNames(); }
+
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBObjectStore> createObjectStore(const String& name, ExceptionCode& ec) { return createObjectStore(name, OptionsObject(), ec); }
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext* context, ExceptionCode& ec) { return transaction(context, OptionsObject(), ec); }
+
+ PassRefPtr<IDBObjectStore> createObjectStore(const String& name, const OptionsObject&, ExceptionCode&);
+ void deleteObjectStore(const String& name, ExceptionCode&);
+ PassRefPtr<IDBRequest> setVersion(ScriptExecutionContext*, const String& version, ExceptionCode&);
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext*, const OptionsObject&, ExceptionCode&);
+ void close();
+
+private:
+ IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface>);
+
+ RefPtr<IDBDatabaseBackendInterface> m_backend;
+ RefPtr<IDBTransactionBackendInterface> m_setVersionTransaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabase_h
diff --git a/Source/WebCore/storage/IDBDatabase.idl b/Source/WebCore/storage/IDBDatabase.idl
new file mode 100644
index 0000000..c6edd48
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabase.idl
@@ -0,0 +1,47 @@
+/*
+ * 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
+ ] IDBDatabase {
+ readonly attribute DOMString name;
+ readonly attribute DOMString version;
+ readonly attribute DOMStringList objectStoreNames;
+
+ IDBObjectStore createObjectStore(in DOMString name, in [Optional] OptionsObject options)
+ raises (IDBDatabaseException);
+ void deleteObjectStore(in DOMString name)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest setVersion(in DOMString version)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBTransaction transaction (in [Optional] OptionsObject optionsObject)
+ raises (IDBDatabaseException);
+ // FIXME: Implement.
+ //void close();
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp
new file mode 100644
index 0000000..fa9a336
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseBackendImpl.cpp
@@ -0,0 +1,294 @@
+/*
+ * 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 "IDBDatabaseBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
+#include "DOMStringList.h"
+#include "IDBDatabaseException.h"
+#include "IDBFactoryBackendImpl.h"
+#include "IDBObjectStoreBackendImpl.h"
+#include "IDBSQLiteDatabase.h"
+#include "IDBTransactionBackendImpl.h"
+#include "IDBTransactionCoordinator.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+
+namespace WebCore {
+
+static bool extractMetaData(SQLiteDatabase& sqliteDatabase, const String& name, String& foundVersion, int64& foundId)
+{
+ SQLiteStatement databaseQuery(sqliteDatabase, "SELECT id, version FROM Databases WHERE name = ?");
+ if (databaseQuery.prepare() != SQLResultOk) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ databaseQuery.bindText(1, name);
+ if (databaseQuery.step() != SQLResultRow)
+ return false;
+
+ foundId = databaseQuery.getColumnInt64(0);
+ foundVersion = databaseQuery.getColumnText(1);
+
+ if (databaseQuery.step() == SQLResultRow)
+ ASSERT_NOT_REACHED();
+ return true;
+}
+
+static bool setMetaData(SQLiteDatabase& sqliteDatabase, const String& name, const String& version, int64_t& rowId)
+{
+ ASSERT(!name.isNull());
+ ASSERT(!version.isNull());
+
+ String sql = rowId != IDBDatabaseBackendImpl::InvalidId ? "UPDATE Databases SET name = ?, version = ? WHERE id = ?"
+ : "INSERT INTO Databases (name, description, version) VALUES (?, '', ?)";
+ SQLiteStatement query(sqliteDatabase, sql);
+ if (query.prepare() != SQLResultOk) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ query.bindText(1, name);
+ query.bindText(2, version);
+ if (rowId != IDBDatabaseBackendImpl::InvalidId)
+ query.bindInt64(3, rowId);
+
+ if (query.step() != SQLResultDone)
+ return false;
+
+ if (rowId == IDBDatabaseBackendImpl::InvalidId)
+ rowId = sqliteDatabase.lastInsertRowID();
+
+ return true;
+}
+
+IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBSQLiteDatabase* sqliteDatabase, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
+ : m_sqliteDatabase(sqliteDatabase)
+ , m_id(InvalidId)
+ , m_name(name)
+ , m_version("")
+ , m_identifier(uniqueIdentifier)
+ , m_factory(factory)
+ , m_transactionCoordinator(coordinator)
+{
+ ASSERT(!m_name.isNull());
+
+ bool success = extractMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id);
+ ASSERT_UNUSED(success, success == (m_id != InvalidId));
+ if (!setMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id))
+ ASSERT_NOT_REACHED(); // FIXME: Need better error handling.
+ loadObjectStores();
+}
+
+IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
+{
+ m_factory->removeIDBDatabaseBackend(m_identifier);
+}
+
+SQLiteDatabase& IDBDatabaseBackendImpl::sqliteDatabase() const
+{
+ return m_sqliteDatabase->db();
+}
+
+PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStoreNames() 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();
+}
+
+PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ ASSERT(transactionPtr->mode() == IDBTransaction::VERSION_CHANGE);
+
+ if (m_objectStores.contains(name)) {
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), name, keyPath, autoIncrement);
+ ASSERT(objectStore->name() == name);
+
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::createObjectStoreInternal, database, objectStore, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::removeObjectStoreFromMap, database, objectStore))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ m_objectStores.set(name, objectStore);
+ return objectStore.release();
+}
+
+void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)");
+ if (insert.prepare() != SQLResultOk) {
+ transaction->abort();
+ return;
+ }
+ insert.bindText(1, objectStore->name());
+ insert.bindText(2, objectStore->keyPath());
+ insert.bindInt(3, static_cast<int>(objectStore->autoIncrement()));
+ insert.bindInt64(4, database->id());
+ if (insert.step() != SQLResultDone) {
+ transaction->abort();
+ return;
+ }
+ int64_t id = database->sqliteDatabase().lastInsertRowID();
+ objectStore->setId(id);
+ transaction->didCompleteTaskEvents();
+}
+
+PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name)
+{
+ return m_objectStores.get(name);
+}
+
+static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
+{
+ SQLiteStatement deleteQuery(db, sql);
+ bool ok = deleteQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ deleteQuery.bindInt64(1, id);
+ ok = deleteQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+}
+
+void IDBDatabaseBackendImpl::deleteObjectStore(const String& name, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name);
+ if (!objectStore) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return;
+ }
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::deleteObjectStoreInternal, database, objectStore, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::addObjectStoreToMap, database, objectStore))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+ m_objectStores.remove(name);
+}
+
+void IDBDatabaseBackendImpl::deleteObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id());
+
+ transaction->didCompleteTaskEvents();
+}
+
+void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<DOMStringList> objectStoreNames = DOMStringList::create();
+ RefPtr<IDBTransactionBackendInterface> transaction = IDBTransactionBackendImpl::create(objectStoreNames.get(), IDBTransaction::VERSION_CHANGE, 0, this);
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::setVersionInternal, database, version, callbacks, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::resetVersion, database, m_version))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ }
+}
+
+void IDBDatabaseBackendImpl::setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, const String& version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ int64_t databaseId = database->id();
+ database->m_version = version;
+ if (!setMetaData(database->m_sqliteDatabase->db(), database->m_name, database->m_version, databaseId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+ callbacks->onSuccess(transaction);
+}
+
+PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList* objectStoreNames, unsigned short mode, unsigned long timeout, ExceptionCode& ec)
+{
+ for (size_t i = 0; i < objectStoreNames->length(); ++i) {
+ if (!m_objectStores.contains(objectStoreNames->item(i))) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return 0;
+ }
+ }
+
+ // FIXME: Return not allowed err if close has been called.
+ return IDBTransactionBackendImpl::create(objectStoreNames, mode, timeout, this);
+}
+
+void IDBDatabaseBackendImpl::close()
+{
+ // FIXME: Implement.
+}
+
+void IDBDatabaseBackendImpl::loadObjectStores()
+{
+ SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?");
+ bool ok = objectStoresQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ objectStoresQuery.bindInt64(1, m_id);
+
+ while (objectStoresQuery.step() == SQLResultRow) {
+ int64_t id = objectStoresQuery.getColumnInt64(0);
+ String name = objectStoresQuery.getColumnText(1);
+ String keyPath = objectStoresQuery.getColumnText(2);
+ bool autoIncrement = !!objectStoresQuery.getColumnInt(3);
+
+ m_objectStores.set(name, IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), id, name, keyPath, autoIncrement));
+ }
+}
+
+void IDBDatabaseBackendImpl::removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
+{
+ ASSERT(database->m_objectStores.contains(objectStore->name()));
+ database->m_objectStores.remove(objectStore->name());
+}
+
+void IDBDatabaseBackendImpl::addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStorePtr = objectStore;
+ ASSERT(!database->m_objectStores.contains(objectStorePtr->name()));
+ database->m_objectStores.set(objectStorePtr->name(), objectStorePtr);
+}
+
+void IDBDatabaseBackendImpl::resetVersion(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, const String& version)
+{
+ database->m_version = version;
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBDatabaseBackendImpl.h b/Source/WebCore/storage/IDBDatabaseBackendImpl.h
new file mode 100644
index 0000000..570f6a5
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseBackendImpl.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 IDBDatabaseBackendImpl_h
+#define IDBDatabaseBackendImpl_h
+
+#include "IDBCallbacks.h"
+#include "IDBDatabase.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBFactoryBackendImpl;
+class IDBObjectStoreBackendImpl;
+class IDBSQLiteDatabase;
+class IDBTransactionCoordinator;
+class SQLiteDatabase;
+
+class IDBDatabaseBackendImpl : public IDBDatabaseBackendInterface {
+public:
+ static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, IDBSQLiteDatabase* database, IDBTransactionCoordinator* coordinator, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
+ {
+ return adoptRef(new IDBDatabaseBackendImpl(name, database, coordinator, factory, uniqueIdentifier));
+ }
+ virtual ~IDBDatabaseBackendImpl();
+
+ SQLiteDatabase& sqliteDatabase() const;
+
+ static const int64_t InvalidId = 0;
+ int64_t id() const { return m_id; }
+
+ virtual String name() const { return m_name; }
+ virtual String version() const { return m_version; }
+ virtual PassRefPtr<DOMStringList> objectStoreNames() const;
+
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void deleteObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* objectStoreNames, unsigned short mode, unsigned long timeout, ExceptionCode&);
+ virtual void close();
+
+ PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name);
+ IDBTransactionCoordinator* transactionCoordinator() const { return m_transactionCoordinator.get(); }
+
+private:
+ IDBDatabaseBackendImpl(const String& name, IDBSQLiteDatabase* database, IDBTransactionCoordinator*, IDBFactoryBackendImpl*, const String& uniqueIdentifier);
+
+ void loadObjectStores();
+
+ static void createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void deleteObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+
+ // These are used as setVersion transaction abort tasks.
+ static void removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
+ static void addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
+ static void resetVersion(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version);
+
+ RefPtr<IDBSQLiteDatabase> m_sqliteDatabase;
+ int64 m_id;
+ String m_name;
+ String m_version;
+
+ String m_identifier;
+ // This might not need to be a RefPtr since the factory's lifetime is that of the page group, but it's better to be conservitive than sorry.
+ RefPtr<IDBFactoryBackendImpl> m_factory;
+
+ typedef HashMap<String, RefPtr<IDBObjectStoreBackendImpl> > ObjectStoreMap;
+ ObjectStoreMap m_objectStores;
+
+ RefPtr<IDBTransactionCoordinator> m_transactionCoordinator;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseBackendImpl_h
diff --git a/Source/WebCore/storage/IDBDatabaseBackendInterface.h b/Source/WebCore/storage/IDBDatabaseBackendInterface.h
new file mode 100644
index 0000000..0dc59b1
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseBackendInterface.h
@@ -0,0 +1,68 @@
+/*
+ * 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 IDBDatabaseBackendInterface_h
+#define IDBDatabaseBackendInterface_h
+
+#include "ExceptionCode.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 IDBObjectStoreBackendInterface;
+class IDBTransactionBackendInterface;
+class IDBTransactionCallbacks;
+
+// This class is shared by IDBDatabase (async) and IDBDatabaseSync (sync).
+// This is implemented by IDBDatabaseBackendImpl 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 IDBDatabaseBackendInterface : public ThreadSafeShared<IDBDatabaseBackendInterface> {
+public:
+ virtual ~IDBDatabaseBackendInterface() { }
+
+ virtual String name() const = 0;
+ virtual String version() const = 0;
+ virtual PassRefPtr<DOMStringList> objectStoreNames() const = 0;
+
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void deleteObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout, ExceptionCode&) = 0;
+ virtual void close() = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseBackendInterface_h
diff --git a/Source/WebCore/storage/IDBDatabaseError.h b/Source/WebCore/storage/IDBDatabaseError.h
new file mode 100644
index 0000000..8b42f17
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseError.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 IDBDatabaseError_h
+#define IDBDatabaseError_h
+
+#include "IDBDatabaseException.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseError : public RefCounted<IDBDatabaseError> {
+public:
+ static PassRefPtr<IDBDatabaseError> create(unsigned short code, const String& message)
+ {
+ ASSERT(code >= IDBDatabaseException::IDBDatabaseExceptionOffset);
+ ASSERT(code < IDBDatabaseException::IDBDatabaseExceptionMax);
+ return adoptRef(new IDBDatabaseError(code - IDBDatabaseException::IDBDatabaseExceptionOffset, message));
+ }
+
+ static PassRefPtr<IDBDatabaseError> createWithoutOffset(unsigned short code, const String& message)
+ {
+ ASSERT(code < IDBDatabaseException::IDBDatabaseExceptionOffset);
+ return adoptRef(new IDBDatabaseError(code, message));
+ }
+
+ ~IDBDatabaseError() { }
+
+ unsigned short code() const { return m_code; }
+ void setCode(unsigned short value) { m_code = value; }
+ const String& message() const { return m_message; }
+ void setMessage(const String& value) { m_message = value; }
+
+private:
+ IDBDatabaseError(unsigned short code, const String& message)
+ : m_code(code), m_message(message) { }
+
+ unsigned short m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseError_h
diff --git a/Source/WebCore/storage/IDBDatabaseError.idl b/Source/WebCore/storage/IDBDatabaseError.idl
new file mode 100644
index 0000000..2912a1d
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseError.idl
@@ -0,0 +1,35 @@
+/*
+ * 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
+ ] IDBDatabaseError {
+ attribute unsigned short code;
+ attribute DOMString message;
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBDatabaseException.h b/Source/WebCore/storage/IDBDatabaseException.h
new file mode 100644
index 0000000..936b05a
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseException.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 IDBDatabaseException_h
+#define IDBDatabaseException_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+class IDBDatabaseException : public ExceptionBase {
+public:
+ static PassRefPtr<IDBDatabaseException> create(const ExceptionCodeDescription& description)
+ {
+ return adoptRef(new IDBDatabaseException(description));
+ }
+
+ static const int IDBDatabaseExceptionOffset = 1200;
+ static const int IDBDatabaseExceptionMax = 1299;
+
+ enum IDBDatabaseExceptionCode {
+ UNKNOWN_ERR = IDBDatabaseExceptionOffset + 1,
+ NON_TRANSIENT_ERR = IDBDatabaseExceptionOffset + 2,
+ NOT_FOUND_ERR = IDBDatabaseExceptionOffset + 3,
+ CONSTRAINT_ERR = IDBDatabaseExceptionOffset + 4,
+ DATA_ERR = IDBDatabaseExceptionOffset + 5,
+ NOT_ALLOWED_ERR = IDBDatabaseExceptionOffset + 6,
+ SERIAL_ERR = IDBDatabaseExceptionOffset + 7,
+ RECOVERABLE_ERR = IDBDatabaseExceptionOffset + 8,
+ TRANSIENT_ERR = IDBDatabaseExceptionOffset + 9,
+ TIMEOUT_ERR = IDBDatabaseExceptionOffset + 10,
+ DEADLOCK_ERR = IDBDatabaseExceptionOffset + 11
+ };
+
+ static int ErrorCodeToExceptionCode(int errorCode)
+ {
+ if (!errorCode)
+ return 0;
+ return errorCode + IDBDatabaseExceptionOffset;
+ }
+
+private:
+ IDBDatabaseException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBDatabaseException_h
diff --git a/Source/WebCore/storage/IDBDatabaseException.idl b/Source/WebCore/storage/IDBDatabaseException.idl
new file mode 100644
index 0000000..a56f4c7
--- /dev/null
+++ b/Source/WebCore/storage/IDBDatabaseException.idl
@@ -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.
+ *
+ * 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,
+ DontCheckEnums
+ ] IDBDatabaseException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ // Override in a Mozilla compatible format
+ [DontEnum] DOMString toString();
+#endif
+
+ const unsigned short UNKNOWN_ERR = 1;
+ const unsigned short NON_TRANSIENT_ERR = 2;
+ const unsigned short NOT_FOUND_ERR = 3;
+ const unsigned short CONSTRAINT_ERR = 4;
+ const unsigned short DATA_ERR = 5;
+ const unsigned short NOT_ALLOWED_ERR = 6;
+ const unsigned short SERIAL_ERR = 7;
+ const unsigned short RECOVERABLE_ERR = 8;
+ const unsigned short TRANSIENT_ERR = 9;
+ const unsigned short TIMEOUT_ERR = 10;
+ const unsigned short DEADLOCK_ERR = 11;
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBErrorEvent.cpp b/Source/WebCore/storage/IDBErrorEvent.cpp
new file mode 100644
index 0000000..cba980d
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBErrorEvent.h b/Source/WebCore/storage/IDBErrorEvent.h
new file mode 100644
index 0000000..648da8b
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBErrorEvent.idl b/Source/WebCore/storage/IDBErrorEvent.idl
new file mode 100644
index 0000000..5c58f6f
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBEvent.cpp b/Source/WebCore/storage/IDBEvent.cpp
new file mode 100644
index 0000000..f9f6060
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBEvent.h b/Source/WebCore/storage/IDBEvent.h
new file mode 100644
index 0000000..c44e449
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBEvent.idl b/Source/WebCore/storage/IDBEvent.idl
new file mode 100644
index 0000000..4dd552e
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBFactory.cpp b/Source/WebCore/storage/IDBFactory.cpp
new file mode 100644
index 0000000..85e976c
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactory.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "IDBFactory.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "DOMStringList.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "GroupSettings.h"
+#include "IDBDatabase.h"
+#include "IDBDatabaseException.h"
+#include "IDBFactoryBackendInterface.h"
+#include "IDBKeyRange.h"
+#include "IDBRequest.h"
+#include "Page.h"
+#include "PageGroup.h"
+
+namespace WebCore {
+
+IDBFactory::IDBFactory(IDBFactoryBackendInterface* factory)
+ : m_factoryBackend(factory)
+{
+ // We pass a reference to this object before it can be adopted.
+ relaxAdoptionRequirement();
+}
+
+IDBFactory::~IDBFactory()
+{
+}
+
+PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const String& name, ExceptionCode& ec)
+{
+ if (!context->isDocument()) {
+ // FIXME: make this work with workers.
+ return 0;
+ }
+
+ Document* document = static_cast<Document*>(context);
+ if (!document->frame() || !document->page())
+ return 0;
+
+
+ // FIXME: Raise a NON_TRANSIENT_ERR if the name is invalid.
+
+
+ RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this), 0);
+ GroupSettings* groupSettings = document->page()->group().groupSettings();
+ m_factoryBackend->open(name, request, document->securityOrigin(), document->frame(), groupSettings->indexedDBDatabasePath(), groupSettings->indexedDBQuotaBytes());
+ return request;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBFactory.h b/Source/WebCore/storage/IDBFactory.h
new file mode 100644
index 0000000..cd0d64f
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactory.h
@@ -0,0 +1,70 @@
+/*
+ * 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 IDBFactory_h
+#define IDBFactory_h
+
+#include "DOMStringList.h"
+#include "ExceptionCode.h"
+#include "IDBFactoryBackendInterface.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 IDBKey;
+class IDBKeyRange;
+class IDBFactoryBackendInterface;
+class ScriptExecutionContext;
+
+class IDBFactory : public RefCounted<IDBFactory> {
+public:
+ static PassRefPtr<IDBFactory> create(IDBFactoryBackendInterface* factory)
+ {
+ return adoptRef(new IDBFactory(factory));
+ }
+ ~IDBFactory();
+
+ PassRefPtr<IDBRequest> open(ScriptExecutionContext*, const String& name, ExceptionCode&);
+
+private:
+ IDBFactory(IDBFactoryBackendInterface*);
+
+ RefPtr<IDBFactoryBackendInterface> m_factoryBackend;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBFactory_h
+
diff --git a/Source/WebCore/storage/IDBFactory.idl b/Source/WebCore/storage/IDBFactory.idl
new file mode 100644
index 0000000..02eed0e
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactory.idl
@@ -0,0 +1,35 @@
+/*
+ * 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
+ ] IDBFactory {
+ [CallWith=ScriptExecutionContext] IDBRequest open(in DOMString name)
+ raises (IDBDatabaseException);
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.cpp b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp
new file mode 100644
index 0000000..45cffeb
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactoryBackendImpl.cpp
@@ -0,0 +1,240 @@
+/*
+ * 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 "IDBFactoryBackendImpl.h"
+
+#include "DOMStringList.h"
+#include "FileSystem.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseException.h"
+#include "IDBSQLiteDatabase.h"
+#include "IDBTransactionCoordinator.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+#include "SecurityOrigin.h"
+#include <wtf/Threading.h>
+#include <wtf/UnusedParam.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IDBFactoryBackendImpl::IDBFactoryBackendImpl()
+ : m_transactionCoordinator(IDBTransactionCoordinator::create())
+{
+}
+
+IDBFactoryBackendImpl::~IDBFactoryBackendImpl()
+{
+}
+
+void IDBFactoryBackendImpl::removeIDBDatabaseBackend(const String& uniqueIdentifier)
+{
+ ASSERT(m_databaseBackendMap.contains(uniqueIdentifier));
+ m_databaseBackendMap.remove(uniqueIdentifier);
+}
+
+void IDBFactoryBackendImpl::removeSQLiteDatabase(const String& uniqueIdentifier)
+{
+ ASSERT(m_sqliteDatabaseMap.contains(uniqueIdentifier));
+ m_sqliteDatabaseMap.remove(uniqueIdentifier);
+}
+
+static PassRefPtr<IDBSQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory)
+{
+ String path = ":memory:";
+ if (!pathBase.isEmpty()) {
+ if (!makeAllDirectories(pathBase)) {
+ // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out.
+ LOG_ERROR("Unabled to create LocalStorage database path %s", pathBase.utf8().data());
+ return 0;
+ }
+
+ path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb");
+ }
+
+ RefPtr<IDBSQLiteDatabase> sqliteDatabase = IDBSQLiteDatabase::create(fileIdentifier, factory);
+ if (!sqliteDatabase->db().open(path)) {
+ // FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out.
+ LOG_ERROR("Failed to open database file %s for IndexedDB", path.utf8().data());
+ return 0;
+ }
+
+ // FIXME: Error checking?
+ sqliteDatabase->db().setMaximumSize(maximumSize);
+ sqliteDatabase->db().turnOnIncrementalAutoVacuum();
+
+ return sqliteDatabase.release();
+}
+
+static bool createTables(SQLiteDatabase& sqliteDatabase)
+{
+ if (sqliteDatabase.tableExists("Databases"))
+ return true;
+
+ static const char* commands[] = {
+ "CREATE TABLE Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)",
+ "CREATE UNIQUE INDEX Databases_name ON Databases(name)",
+
+ "CREATE TABLE ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))",
+ "CREATE UNIQUE INDEX ObjectStores_composit ON ObjectStores(databaseId, name)",
+
+ "CREATE TABLE Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)",
+ "CREATE UNIQUE INDEX Indexes_composit ON Indexes(objectStoreId, name)",
+
+ "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)",
+ "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
+
+ "CREATE TABLE IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
+ "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
+ "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
+ "CREATE INDEX IndexData_indexId ON IndexData(indexId)",
+ };
+
+ SQLiteTransaction transaction(sqliteDatabase, false);
+ transaction.begin();
+ for (size_t i = 0; i < arraysize(commands); ++i) {
+ if (!sqliteDatabase.executeCommand(commands[i])) {
+ // FIXME: We should try to recover from this situation. Maybe nuke the database and start over?
+ LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]);
+ return false;
+ }
+ }
+ transaction.commit();
+ return true;
+}
+
+static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase)
+{
+ static const char* commands[] = {
+ "CREATE TABLE MetaData (name TEXT PRIMARY KEY, value NONE)",
+ "INSERT INTO MetaData VALUES ('version', 1)",
+ };
+
+ SQLiteTransaction transaction(sqliteDatabase, false);
+ transaction.begin();
+ for (size_t i = 0; i < arraysize(commands); ++i) {
+ if (!sqliteDatabase.executeCommand(commands[i]))
+ return false;
+ }
+ transaction.commit();
+ return true;
+}
+
+static bool getDatabaseVersion(SQLiteDatabase& sqliteDatabase, int* databaseVersion)
+{
+ SQLiteStatement query(sqliteDatabase, "SELECT value FROM MetaData WHERE name = 'version'");
+ if (query.prepare() != SQLResultOk || query.step() != SQLResultRow)
+ return false;
+
+ *databaseVersion = query.getColumnInt(0);
+ return query.finalize() == SQLResultOk;
+}
+
+static bool migrateDatabase(SQLiteDatabase& sqliteDatabase)
+{
+ if (!sqliteDatabase.tableExists("MetaData")) {
+ if (!createMetaDataTable(sqliteDatabase))
+ return false;
+ }
+
+ int databaseVersion;
+ if (!getDatabaseVersion(sqliteDatabase, &databaseVersion))
+ return false;
+
+ if (databaseVersion == 1) {
+ static const char* commands[] = {
+ "DROP TABLE IF EXISTS ObjectStoreData2",
+ "CREATE TABLE ObjectStoreData2 (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, keyNumber REAL, value TEXT NOT NULL)",
+ "INSERT INTO ObjectStoreData2 SELECT * FROM ObjectStoreData",
+ "DROP TABLE ObjectStoreData", // This depends on SQLite not enforcing referential consistency.
+ "ALTER TABLE ObjectStoreData2 RENAME TO ObjectStoreData",
+ "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
+ "DROP TABLE IF EXISTS IndexData2", // This depends on SQLite not enforcing referential consistency.
+ "CREATE TABLE IndexData2 (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate REAL, keyNumber REAL, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
+ "INSERT INTO IndexData2 SELECT * FROM IndexData",
+ "DROP TABLE IndexData",
+ "ALTER TABLE IndexData2 RENAME TO IndexData",
+ "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
+ "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
+ "CREATE INDEX IndexData_indexId ON IndexData(indexId)",
+ "UPDATE MetaData SET value = 2 WHERE name = 'version'",
+ };
+
+ SQLiteTransaction transaction(sqliteDatabase, false);
+ transaction.begin();
+ for (size_t i = 0; i < arraysize(commands); ++i) {
+ if (!sqliteDatabase.executeCommand(commands[i])) {
+ LOG_ERROR("Failed to run the following command for IndexedDB: %s", commands[i]);
+ return false;
+ }
+ }
+ transaction.commit();
+
+ databaseVersion = 2;
+ }
+
+ return true;
+}
+
+void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize)
+{
+ String fileIdentifier = securityOrigin->databaseIdentifier();
+ String uniqueIdentifier = fileIdentifier + "@" + name;
+ IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
+ if (it != m_databaseBackendMap.end()) {
+ callbacks->onSuccess(it->second);
+ return;
+ }
+
+ // FIXME: Everything from now on should be done on another thread.
+
+ RefPtr<IDBSQLiteDatabase> sqliteDatabase;
+ SQLiteDatabaseMap::iterator it2 = m_sqliteDatabaseMap.find(fileIdentifier);
+ if (it2 != m_sqliteDatabaseMap.end())
+ sqliteDatabase = it2->second;
+ else {
+ sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this);
+
+ if (!sqliteDatabase || !createTables(sqliteDatabase->db()) || !migrateDatabase(sqliteDatabase->db())) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+ m_sqliteDatabaseMap.set(fileIdentifier, 0);
+ return;
+ }
+ m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get());
+ }
+
+ RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, sqliteDatabase.get(), m_transactionCoordinator.get(), this, uniqueIdentifier);
+ callbacks->onSuccess(databaseBackend.get());
+ m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBFactoryBackendImpl.h b/Source/WebCore/storage/IDBFactoryBackendImpl.h
new file mode 100644
index 0000000..dcaf848
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactoryBackendImpl.h
@@ -0,0 +1,79 @@
+/*
+ * 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 IDBFactoryBackendImpl_h
+#define IDBFactoryBackendImpl_h
+
+#include "IDBFactoryBackendInterface.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+
+class IDBDatabaseBackendImpl;
+class IDBSQLiteDatabase;
+class IDBTransactionCoordinator;
+
+class IDBFactoryBackendImpl : public IDBFactoryBackendInterface {
+public:
+ static PassRefPtr<IDBFactoryBackendImpl> create()
+ {
+ return adoptRef(new IDBFactoryBackendImpl());
+ }
+ virtual ~IDBFactoryBackendImpl();
+
+ // Notifications from weak pointers.
+ void removeIDBDatabaseBackend(const String& uniqueIdentifier);
+ void removeSQLiteDatabase(const String& uniqueIdentifier);
+
+ virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize);
+
+private:
+ IDBFactoryBackendImpl();
+
+ typedef HashMap<String, IDBDatabaseBackendImpl*> IDBDatabaseBackendMap;
+ IDBDatabaseBackendMap m_databaseBackendMap;
+
+ typedef HashMap<String, IDBSQLiteDatabase*> SQLiteDatabaseMap;
+ SQLiteDatabaseMap m_sqliteDatabaseMap;
+
+ RefPtr<IDBTransactionCoordinator> m_transactionCoordinator;
+
+ // Only one instance of the factory should exist at any given time.
+ static IDBFactoryBackendImpl* idbFactoryBackendImpl;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBFactoryBackendImpl_h
+
diff --git a/Source/WebCore/storage/IDBFactoryBackendInterface.cpp b/Source/WebCore/storage/IDBFactoryBackendInterface.cpp
new file mode 100644
index 0000000..935ccac
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactoryBackendInterface.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "IDBFactoryBackendInterface.h"
+
+#include "IDBFactoryBackendImpl.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<IDBFactoryBackendInterface> IDBFactoryBackendInterface::create()
+{
+ return IDBFactoryBackendImpl::create();
+}
+
+IDBFactoryBackendInterface::~IDBFactoryBackendInterface()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBFactoryBackendInterface.h b/Source/WebCore/storage/IDBFactoryBackendInterface.h
new file mode 100644
index 0000000..166d517
--- /dev/null
+++ b/Source/WebCore/storage/IDBFactoryBackendInterface.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 IDBFactoryBackendInterface_h
+#define IDBFactoryBackendInterface_h
+
+#include "ExceptionCode.h"
+#include "IDBCallbacks.h"
+#include "PlatformString.h"
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class Frame;
+class IDBDatabase;
+class SecurityOrigin;
+
+// This class is shared by IDBFactory (async) and IDBFactorySync (sync).
+// This is implemented by IDBFactoryBackendImpl 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 IDBFactoryBackendInterface : public ThreadSafeShared<IDBFactoryBackendInterface> {
+public:
+ static PassRefPtr<IDBFactoryBackendInterface> create();
+ virtual ~IDBFactoryBackendInterface();
+
+ virtual void open(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBFactoryBackendInterface_h
diff --git a/Source/WebCore/storage/IDBIndex.cpp b/Source/WebCore/storage/IDBIndex.cpp
new file mode 100644
index 0000000..8a38a27
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndex.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 "IDBIndex.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCursorBackendInterface.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndexBackendInterface.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
+#include "IDBRequest.h"
+#include "IDBTransactionBackendInterface.h"
+
+namespace WebCore {
+
+static const unsigned short defaultDirection = IDBCursor::NEXT;
+
+IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend, IDBTransactionBackendInterface* transaction)
+ : m_backend(backend)
+ , m_transaction(transaction)
+{
+ ASSERT(m_backend);
+ ASSERT(m_transaction);
+}
+
+IDBIndex::~IDBIndex()
+{
+}
+
+PassRefPtr<IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, const OptionsObject& options, ExceptionCode& ec)
+{
+ RefPtr<IDBKeyRange> keyRange = options.getKeyKeyRange("range");
+
+ // Converted to an unsigned short.
+ int32_t direction = defaultDirection;
+ options.getKeyInt32("direction", direction);
+ if (direction != IDBCursor::NEXT && direction != IDBCursor::NEXT_NO_DUPLICATE && direction != IDBCursor::PREV && direction != IDBCursor::PREV_NO_DUPLICATE) {
+ // FIXME: May need to change when specced: http://www.w3.org/Bugs/Public/show_bug.cgi?id=11406
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->openCursor(keyRange, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, const OptionsObject& options, ExceptionCode& ec)
+{
+ RefPtr<IDBKeyRange> keyRange = options.getKeyKeyRange("range");
+
+ // Converted to an unsigned short.
+ int32_t direction = defaultDirection;
+ options.getKeyInt32("direction", direction);
+ if (direction != IDBCursor::NEXT && direction != IDBCursor::NEXT_NO_DUPLICATE && direction != IDBCursor::PREV && direction != IDBCursor::PREV_NO_DUPLICATE) {
+ // FIXME: May need to change when specced: http://www.w3.org/Bugs/Public/show_bug.cgi?id=11406
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->openKeyCursor(keyRange, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->get(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->getKey(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBIndex.h b/Source/WebCore/storage/IDBIndex.h
new file mode 100644
index 0000000..7f1aae3
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndex.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 IDBIndex_h
+#define IDBIndex_h
+
+#include "IDBCursor.h"
+#include "IDBIndexBackendInterface.h"
+#include "IDBKeyRange.h"
+#include "IDBRequest.h"
+#include "OptionsObject.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBIndex : public RefCounted<IDBIndex> {
+public:
+ static PassRefPtr<IDBIndex> create(PassRefPtr<IDBIndexBackendInterface> backend, IDBTransactionBackendInterface* transaction)
+ {
+ return adoptRef(new IDBIndex(backend, transaction));
+ }
+ ~IDBIndex();
+
+ // Implement the IDL
+ String name() const { return m_backend->name(); }
+ String storeName() const { return m_backend->storeName(); }
+ String keyPath() const { return m_backend->keyPath(); }
+ bool unique() const { return m_backend->unique(); }
+
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, OptionsObject(), ec); }
+ PassRefPtr<IDBRequest> openKeyCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openKeyCursor(context, OptionsObject(), ec); }
+
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, const OptionsObject&, ExceptionCode&);
+ PassRefPtr<IDBRequest> openKeyCursor(ScriptExecutionContext*, const OptionsObject&, ExceptionCode&);
+ PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> getKey(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
+
+private:
+ IDBIndex(PassRefPtr<IDBIndexBackendInterface>, IDBTransactionBackendInterface* transaction);
+
+ RefPtr<IDBIndexBackendInterface> m_backend;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndex_h
diff --git a/Source/WebCore/storage/IDBIndex.idl b/Source/WebCore/storage/IDBIndex.idl
new file mode 100644
index 0000000..e6ba1e6
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndex.idl
@@ -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.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE
+ ] IDBIndex {
+ readonly attribute DOMString name;
+ readonly attribute DOMString storeName;
+ readonly attribute DOMString keyPath;
+ readonly attribute boolean unique;
+
+ [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] OptionsObject options)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest openKeyCursor(in [Optional] OptionsObject options)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest getKey(in IDBKey key)
+ raises (IDBDatabaseException);
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBIndexBackendImpl.cpp b/Source/WebCore/storage/IDBIndexBackendImpl.cpp
new file mode 100644
index 0000000..df88fdb
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndexBackendImpl.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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 "IDBIndexBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
+#include "IDBCallbacks.h"
+#include "IDBCursorBackendImpl.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseException.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
+#include "IDBObjectStoreBackendImpl.h"
+#include "IDBSQLiteDatabase.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+
+namespace WebCore {
+
+IDBIndexBackendImpl::IDBIndexBackendImpl(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique)
+ : m_database(database)
+ , m_id(id)
+ , m_name(name)
+ , m_storeName(storeName)
+ , m_keyPath(keyPath)
+ , m_unique(unique)
+{
+}
+
+IDBIndexBackendImpl::IDBIndexBackendImpl(IDBSQLiteDatabase* database, const String& name, const String& storeName, const String& keyPath, bool unique)
+ : m_database(database)
+ , m_id(InvalidId)
+ , m_name(name)
+ , m_storeName(storeName)
+ , m_keyPath(keyPath)
+ , m_unique(unique)
+{
+}
+
+IDBIndexBackendImpl::~IDBIndexBackendImpl()
+{
+}
+
+void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, bool objectCursor, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ // Several files depend on this order of selects.
+ String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
+ + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
+ + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE ";
+
+ bool lowerBound = range && range->lower();
+ bool upperBound = range && range->upper();
+
+ if (lowerBound)
+ sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator(), "IndexData.");
+ if (upperBound)
+ sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator(), "IndexData.");
+ sql += "IndexData.indexId = ? ORDER BY ";
+
+ IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
+ if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
+ sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id";
+ else
+ sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
+
+ OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(index->sqliteDatabase(), sql));
+ bool ok = query->prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ int indexColumn = 1;
+ if (lowerBound)
+ indexColumn += range->lower()->bind(*query, indexColumn);
+ if (upperBound)
+ indexColumn += range->upper()->bind(*query, indexColumn);
+ query->bindInt64(indexColumn, index->id());
+
+ if (query->step() != SQLResultRow) {
+ callbacks->onSuccess();
+ return;
+ }
+
+ ExceptionCode ec = 0;
+ RefPtr<IDBObjectStoreBackendInterface> objectStore = transaction->objectStore(index->m_storeName, ec);
+ ASSERT(objectStore && !ec);
+
+ RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index->m_database.get(), range, direction, query.release(), objectCursor, transaction.get(), objectStore.get());
+ callbacks->onSuccess(cursor.release());
+}
+
+void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKeyRange> keyRange = prpKeyRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, true, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKeyRange> keyRange = prpKeyRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, false, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks)
+{
+ String sql = String("SELECT ")
+ + (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
+ + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
+ + "WHERE IndexData.indexId = ? AND " + key->whereSyntax("IndexData.")
+ + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
+ SQLiteStatement query(index->sqliteDatabase(), sql);
+ bool ok = query.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ query.bindInt64(1, index->id());
+ key->bind(query, 2);
+ if (query.step() != SQLResultRow) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
+ return;
+ }
+
+ if (getObject)
+ callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0)));
+ else
+ callbacks->onSuccess(IDBKey::fromQuery(query, 0));
+ ASSERT(query.step() != SQLResultRow);
+}
+
+void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, true, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, false, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+static String whereClause(IDBKey* key)
+{
+ return "WHERE indexId = ? AND " + key->whereSyntax();
+}
+
+static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)
+{
+ query.bindInt64(1, id);
+ key->bind(query, 2);
+}
+
+bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key)
+{
+ if (!m_unique)
+ return true;
+
+ SQLiteStatement query(sqliteDatabase(), "SELECT id FROM IndexData " + whereClause(key));
+ bool ok = query.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ bindWhereClause(query, m_id, key);
+ bool existingValue = query.step() == SQLResultRow;
+
+ return !existingValue;
+}
+
+SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const
+{
+ return m_database->db();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBIndexBackendImpl.h b/Source/WebCore/storage/IDBIndexBackendImpl.h
new file mode 100644
index 0000000..e640b5a
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndexBackendImpl.h
@@ -0,0 +1,97 @@
+/*
+ * 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 IDBIndexBackendImpl_h
+#define IDBIndexBackendImpl_h
+
+#include "IDBIndexBackendInterface.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBKey;
+class IDBObjectStoreBackendImpl;
+class IDBSQLiteDatabase;
+class SQLiteDatabase;
+class ScriptExecutionContext;
+
+class IDBIndexBackendImpl : public IDBIndexBackendInterface {
+public:
+ static PassRefPtr<IDBIndexBackendImpl> create(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique)
+ {
+ return adoptRef(new IDBIndexBackendImpl(database, id, name, storeName, keyPath, unique));
+ }
+ static PassRefPtr<IDBIndexBackendImpl> create(IDBSQLiteDatabase* database, const String& name, const String& storeName, const String& keyPath, bool unique)
+ {
+ return adoptRef(new IDBIndexBackendImpl(database, name, storeName, keyPath, unique));
+ }
+ virtual ~IDBIndexBackendImpl();
+
+ int64_t id() const
+ {
+ ASSERT(m_id != InvalidId);
+ return m_id;
+ }
+ void setId(int64_t id) { m_id = id; }
+
+ bool addingKeyAllowed(IDBKey*);
+
+ // Implements IDBIndexBackendInterface.
+ virtual String name() { return m_name; }
+ virtual String storeName() { return m_storeName; }
+ virtual String keyPath() { return m_keyPath; }
+ virtual bool unique() { return m_unique; }
+
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void openKeyCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void getKey(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+
+private:
+ IDBIndexBackendImpl(IDBSQLiteDatabase*, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique);
+ IDBIndexBackendImpl(IDBSQLiteDatabase*, const String& name, const String& storeName, const String& keyPath, bool unique);
+
+ SQLiteDatabase& sqliteDatabase() const;
+
+ static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, unsigned short direction, bool objectCursor, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKey>, bool getObject, PassRefPtr<IDBCallbacks>);
+
+ static const int64_t InvalidId = 0;
+
+ RefPtr<IDBSQLiteDatabase> m_database;
+
+ int64_t m_id;
+ String m_name;
+ String m_storeName;
+ String m_keyPath;
+ bool m_unique;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndexBackendImpl_h
diff --git a/Source/WebCore/storage/IDBIndexBackendInterface.h b/Source/WebCore/storage/IDBIndexBackendInterface.h
new file mode 100644
index 0000000..e0e578d
--- /dev/null
+++ b/Source/WebCore/storage/IDBIndexBackendInterface.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.
+ *
+ * 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 IDBIndexBackendInterface_h
+#define IDBIndexBackendInterface_h
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBCallbacks;
+class IDBKey;
+class IDBKeyRange;
+class IDBTransactionBackendInterface;
+
+class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> {
+public:
+ virtual ~IDBIndexBackendInterface() { }
+
+ virtual String name() = 0;
+ virtual String storeName() = 0;
+ virtual String keyPath() = 0;
+ virtual bool unique() = 0;
+
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void openKeyCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void getKey(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBIndexBackendInterface_h
diff --git a/Source/WebCore/storage/IDBKey.cpp b/Source/WebCore/storage/IDBKey.cpp
new file mode 100644
index 0000000..5f45543
--- /dev/null
+++ b/Source/WebCore/storage/IDBKey.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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 "SQLiteStatement.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBKey::IDBKey()
+ : m_type(NullType)
+{
+}
+
+IDBKey::~IDBKey()
+{
+}
+
+PassRefPtr<IDBKey> IDBKey::fromQuery(SQLiteStatement& query, int baseColumn)
+{
+ if (query.columnCount() <= baseColumn)
+ return 0;
+
+ if (!query.isColumnNull(baseColumn))
+ return IDBKey::createString(query.getColumnText(baseColumn));
+
+ if (!query.isColumnNull(baseColumn + 1))
+ return IDBKey::createDate(query.getColumnDouble(baseColumn + 1));
+
+ if (!query.isColumnNull(baseColumn + 2))
+ return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2));
+
+ return IDBKey::createNull();
+}
+
+bool IDBKey::isEqual(IDBKey* other)
+{
+ if (!other || other->m_type != m_type)
+ return false;
+
+ switch (m_type) {
+ case StringType:
+ return other->m_string == m_string;
+ case DateType:
+ return other->m_date == m_date;
+ case NumberType:
+ return other->m_number == m_number;
+ case NullType:
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+String IDBKey::whereSyntax(String qualifiedTableName) const
+{
+ switch (m_type) {
+ case IDBKey::StringType:
+ return qualifiedTableName + "keyString = ? AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL ";
+ case IDBKey::NumberType:
+ return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber = ? ";
+ case IDBKey::DateType:
+ return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate = ? AND " + qualifiedTableName + "keyNumber IS NULL ";
+ case IDBKey::NullType:
+ return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL ";
+ }
+
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+String IDBKey::lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
+{
+ switch (m_type) {
+ case StringType:
+ return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND ";
+ case DateType:
+ return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate OR NOT " + qualifiedTableName + "keyString IS NULL) AND ";
+ case NumberType:
+ return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber OR NOT " + qualifiedTableName + "keyString IS NULL OR NOT " + qualifiedTableName + "keyDate IS NULL) AND ";
+ case NullType:
+ if (comparisonOperator == "<")
+ return "NOT(" + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL) AND ";
+ return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+String IDBKey::upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
+{
+ switch (m_type) {
+ case StringType:
+ return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND ";
+ case DateType:
+ return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND ";
+ case NumberType:
+ return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND ";
+ case NullType:
+ if (comparisonOperator == "<")
+ return "0 != 0 AND ";
+ return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL AND ";
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+// Returns the number of items bound.
+int IDBKey::bind(SQLiteStatement& query, int column) const
+{
+ switch (m_type) {
+ case IDBKey::StringType:
+ query.bindText(column, m_string);
+ return 1;
+ case IDBKey::DateType:
+ query.bindDouble(column, m_date);
+ return 1;
+ case IDBKey::NumberType:
+ query.bindDouble(column, m_number);
+ return 1;
+ case IDBKey::NullType:
+ return 0;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void IDBKey::bindWithNulls(SQLiteStatement& query, int baseColumn) const
+{
+ switch (m_type) {
+ case IDBKey::StringType:
+ query.bindText(baseColumn + 0, m_string);
+ query.bindNull(baseColumn + 1);
+ query.bindNull(baseColumn + 2);
+ break;
+ case IDBKey::DateType:
+ query.bindNull(baseColumn + 0);
+ query.bindDouble(baseColumn + 1, m_date);
+ query.bindNull(baseColumn + 2);
+ break;
+ case IDBKey::NumberType:
+ query.bindNull(baseColumn + 0);
+ query.bindNull(baseColumn + 1);
+ query.bindDouble(baseColumn + 2, m_number);
+ break;
+ case IDBKey::NullType:
+ query.bindNull(baseColumn + 0);
+ query.bindNull(baseColumn + 1);
+ query.bindNull(baseColumn + 2);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBKey.h b/Source/WebCore/storage/IDBKey.h
new file mode 100644
index 0000000..9118743
--- /dev/null
+++ b/Source/WebCore/storage/IDBKey.h
@@ -0,0 +1,127 @@
+/*
+ * 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
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class SQLiteStatement;
+
+class IDBKey : public ThreadSafeShared<IDBKey> {
+public:
+ static PassRefPtr<IDBKey> createNull()
+ {
+ RefPtr<IDBKey> idbKey(new IDBKey());
+ idbKey->m_type = NullType;
+ return idbKey.release();
+ }
+
+ static PassRefPtr<IDBKey> createNumber(double number)
+ {
+ RefPtr<IDBKey> idbKey(new IDBKey());
+ idbKey->m_type = NumberType;
+ idbKey->m_number = number;
+ return idbKey.release();
+ }
+
+ static PassRefPtr<IDBKey> createString(const String& string)
+ {
+ RefPtr<IDBKey> idbKey(new IDBKey());
+ idbKey->m_type = StringType;
+ idbKey->m_string = string;
+ return idbKey.release();
+ }
+
+ static PassRefPtr<IDBKey> createDate(double date)
+ {
+ RefPtr<IDBKey> idbKey(new IDBKey());
+ idbKey->m_type = DateType;
+ idbKey->m_date = date;
+ return idbKey.release();
+ }
+
+ ~IDBKey();
+
+ // In order of the least to the highest precedent in terms of sort order.
+ enum Type {
+ NullType = 0, // FIXME: Phase out support for null keys.
+ StringType,
+ DateType,
+ NumberType
+ };
+
+ Type type() const { return m_type; }
+
+ const String& string() const
+ {
+ ASSERT(m_type == StringType);
+ return m_string;
+ }
+
+ double date() const
+ {
+ ASSERT(m_type == DateType);
+ return m_date;
+ }
+
+ double number() const
+ {
+ ASSERT(m_type == NumberType);
+ return m_number;
+ }
+
+ static PassRefPtr<IDBKey> fromQuery(SQLiteStatement& query, int baseColumn);
+
+ bool isEqual(IDBKey* other);
+ String whereSyntax(String qualifiedTableName = "") const;
+ String lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
+ String upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
+ int bind(SQLiteStatement& query, int column) const;
+ void bindWithNulls(SQLiteStatement& query, int baseColumn) const;
+
+ using ThreadSafeShared<IDBKey>::ref;
+ using ThreadSafeShared<IDBKey>::deref;
+
+private:
+ IDBKey();
+
+ Type m_type;
+ String m_string;
+ double m_date;
+ double m_number;
+};
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBKey_h
diff --git a/Source/WebCore/storage/IDBKey.idl b/Source/WebCore/storage/IDBKey.idl
new file mode 100644
index 0000000..04995f3
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBKeyPath.cpp b/Source/WebCore/storage/IDBKeyPath.cpp
new file mode 100644
index 0000000..8833da0
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyPath.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "IDBKeyPath.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/ASCIICType.h>
+#include <wtf/dtoa.h>
+
+namespace WebCore {
+
+class IDBKeyPathLexer {
+public:
+ enum TokenType {
+ TokenLeftBracket,
+ TokenRightBracket,
+ TokenIdentifier,
+ TokenNumber,
+ TokenDot,
+ TokenEnd,
+ TokenError
+ };
+
+ explicit IDBKeyPathLexer(const String& s)
+ : m_string(s)
+ , m_ptr(s.characters())
+ , m_end(s.characters() + s.length())
+ , m_currentTokenType(TokenError)
+ {
+ }
+
+ TokenType currentTokenType() const { return m_currentTokenType; }
+
+ TokenType nextTokenType()
+ {
+ m_currentTokenType = lex(m_currentElement);
+ return m_currentTokenType;
+ }
+
+ const IDBKeyPathElement& currentElement() { return m_currentElement; }
+
+private:
+ TokenType lex(IDBKeyPathElement&);
+ TokenType lexIdentifier(IDBKeyPathElement&);
+ TokenType lexNumber(IDBKeyPathElement&);
+ IDBKeyPathElement m_currentElement;
+ String m_string;
+ const UChar* m_ptr;
+ const UChar* m_end;
+ TokenType m_currentTokenType;
+};
+
+IDBKeyPathLexer::TokenType IDBKeyPathLexer::lex(IDBKeyPathElement& element)
+{
+ while (m_ptr < m_end && isASCIISpace(*m_ptr))
+ ++m_ptr;
+
+ if (m_ptr >= m_end)
+ return TokenEnd;
+
+ ASSERT(m_ptr < m_end);
+ switch (*m_ptr) {
+ case '[':
+ ++m_ptr;
+ return TokenLeftBracket;
+ case ']':
+ ++m_ptr;
+ return TokenRightBracket;
+ case '.':
+ ++m_ptr;
+ return TokenDot;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return lexNumber(element);
+ default:
+ return lexIdentifier(element);
+ }
+ return TokenError;
+}
+
+static inline bool isSafeIdentifierStartCharacter(UChar c)
+{
+ return isASCIIAlpha(c) || (c == '_') || (c == '$');
+}
+
+static inline bool isSafeIdentifierCharacter(UChar c)
+{
+ return isASCIIAlphanumeric(c) || (c == '_') || (c == '$');
+}
+
+IDBKeyPathLexer::TokenType IDBKeyPathLexer::lexIdentifier(IDBKeyPathElement& element)
+{
+ const UChar* start = m_ptr;
+ if (m_ptr < m_end && isSafeIdentifierStartCharacter(*m_ptr))
+ ++m_ptr;
+ else
+ return TokenError;
+
+ while (m_ptr < m_end && isSafeIdentifierCharacter(*m_ptr))
+ ++m_ptr;
+
+ element.type = IDBKeyPathElement::IsNamed;
+ element.identifier = String(start, m_ptr - start);
+ return TokenIdentifier;
+}
+
+IDBKeyPathLexer::TokenType IDBKeyPathLexer::lexNumber(IDBKeyPathElement& element)
+{
+ if (m_ptr >= m_end)
+ return TokenError;
+
+ const UChar* start = m_ptr;
+ // [0-9]*
+ while (m_ptr < m_end && isASCIIDigit(*m_ptr))
+ ++m_ptr;
+
+ String numberAsString;
+ numberAsString = String(start, m_ptr - start);
+ bool ok = false;
+ unsigned number = numberAsString.toUIntStrict(&ok);
+ if (!ok)
+ return TokenError;
+
+ element.type = IDBKeyPathElement::IsIndexed;
+ element.index = number;
+ return TokenNumber;
+}
+
+void IDBParseKeyPath(const String& keyPath, Vector<IDBKeyPathElement>& elements, IDBKeyPathParseError& error)
+{
+ // This is a simplified parser loosely based on LiteralParser.
+ // An IDBKeyPath is defined as a sequence of:
+ // identifierA{.identifierB{[numeric_value]}
+ // where "{}" represents an optional part
+ // The basic state machine is:
+ // Start => {Identifier, Array}
+ // Identifier => {Dot, Array, End}
+ // Array => {Start, Dot, End}
+ // Dot => {Identifier}
+ // It bails out as soon as it finds an error, but doesn't discard the bits it managed to parse.
+ enum ParserState { Identifier, Array, Dot, End };
+
+ IDBKeyPathLexer lexer(keyPath);
+ IDBKeyPathLexer::TokenType tokenType = lexer.nextTokenType();
+ ParserState state;
+ if (tokenType == IDBKeyPathLexer::TokenIdentifier)
+ state = Identifier;
+ else if (tokenType == IDBKeyPathLexer::TokenLeftBracket)
+ state = Array;
+ else if (tokenType == IDBKeyPathLexer::TokenEnd)
+ state = End;
+ else {
+ error = IDBKeyPathParseErrorStart;
+ return;
+ }
+
+ while (1) {
+ switch (state) {
+ case Identifier : {
+ IDBKeyPathLexer::TokenType tokenType = lexer.currentTokenType();
+ ASSERT(tokenType == IDBKeyPathLexer::TokenIdentifier);
+
+ IDBKeyPathElement element = lexer.currentElement();
+ ASSERT(element.type == IDBKeyPathElement::IsNamed);
+ elements.append(element);
+
+ tokenType = lexer.nextTokenType();
+ if (tokenType == IDBKeyPathLexer::TokenDot)
+ state = Dot;
+ else if (tokenType == IDBKeyPathLexer::TokenLeftBracket)
+ state = Array;
+ else if (tokenType == IDBKeyPathLexer::TokenEnd)
+ state = End;
+ else {
+ error = IDBKeyPathParseErrorIdentifier;
+ return;
+ }
+ break;
+ }
+ case Array : {
+ IDBKeyPathLexer::TokenType tokenType = lexer.currentTokenType();
+ ASSERT(tokenType == IDBKeyPathLexer::TokenLeftBracket);
+
+ tokenType = lexer.nextTokenType();
+ if (tokenType != IDBKeyPathLexer::TokenNumber) {
+ error = IDBKeyPathParseErrorArrayIndex;
+ return;
+ }
+
+ ASSERT(tokenType == IDBKeyPathLexer::TokenNumber);
+ IDBKeyPathElement element = lexer.currentElement();
+ ASSERT(element.type == IDBKeyPathElement::IsIndexed);
+ elements.append(element);
+
+ tokenType = lexer.nextTokenType();
+ if (tokenType != IDBKeyPathLexer::TokenRightBracket) {
+ error = IDBKeyPathParseErrorArrayIndex;
+ return;
+ }
+
+ tokenType = lexer.nextTokenType();
+ if (tokenType == IDBKeyPathLexer::TokenDot)
+ state = Dot;
+ else if (tokenType == IDBKeyPathLexer::TokenLeftBracket)
+ state = Array;
+ else if (tokenType == IDBKeyPathLexer::TokenEnd)
+ state = End;
+ else {
+ error = IDBKeyPathParseErrorAfterArray;
+ return;
+ }
+ break;
+ }
+ case Dot: {
+ IDBKeyPathLexer::TokenType tokenType = lexer.currentTokenType();
+ ASSERT(tokenType == IDBKeyPathLexer::TokenDot);
+
+ tokenType = lexer.nextTokenType();
+ if (tokenType != IDBKeyPathLexer::TokenIdentifier) {
+ error = IDBKeyPathParseErrorDot;
+ return;
+ }
+
+ state = Identifier;
+ break;
+ }
+ case End: {
+ error = IDBKeyPathParseErrorNone;
+ return;
+ }
+ }
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBKeyPath.h b/Source/WebCore/storage/IDBKeyPath.h
new file mode 100644
index 0000000..7787980
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyPath.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 IDBKeyPath_h
+#define IDBKeyPath_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct IDBKeyPathElement {
+ enum Type {
+ IsIndexed,
+ IsNamed,
+ };
+
+ Type type;
+ unsigned index;
+ String identifier;
+};
+
+enum IDBKeyPathParseError {
+ IDBKeyPathParseErrorNone,
+ IDBKeyPathParseErrorStart,
+ IDBKeyPathParseErrorIdentifier,
+ IDBKeyPathParseErrorArrayIndex,
+ IDBKeyPathParseErrorAfterArray,
+ IDBKeyPathParseErrorDot,
+};
+
+void IDBParseKeyPath(const String&, Vector<IDBKeyPathElement>&, IDBKeyPathParseError&);
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBKeyPath_h
diff --git a/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp b/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp
new file mode 100644
index 0000000..b7c45c3
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyPathBackendImpl.cpp
@@ -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:
+ *
+ * 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 "IDBKeyPathBackendImpl.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)
+
+void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>&, 0> values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys)
+{
+ // FIXME: Implement this method once JSC supports WireFormat for SerializedScriptValue.
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBKeyPathBackendImpl.h b/Source/WebCore/storage/IDBKeyPathBackendImpl.h
new file mode 100644
index 0000000..32af5e3
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyPathBackendImpl.h
@@ -0,0 +1,47 @@
+/*
+ * 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 IDBKeyPathBackendImpl_h
+#define IDBKeyPathBackendImpl_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class IDBKey;
+class SerializedScriptValue;
+
+class IDBKeyPathBackendImpl {
+public:
+ static void createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>, 0>& values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys);
+};
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBKeyPathBackendImpl_h
diff --git a/Source/WebCore/storage/IDBKeyRange.cpp b/Source/WebCore/storage/IDBKeyRange.cpp
new file mode 100644
index 0000000..142b3bd
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyRange.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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> lower, PassRefPtr<IDBKey> upper, bool lowerOpen, bool upperOpen)
+ : m_lower(lower)
+ , m_upper(upper)
+ , m_lowerOpen(lowerOpen)
+ , m_upperOpen(upperOpen)
+{
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::only(PassRefPtr<IDBKey> prpValue)
+{
+ RefPtr<IDBKey> value = prpValue;
+ return IDBKeyRange::create(value, value, false, false);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::lowerBound(PassRefPtr<IDBKey> bound, bool open)
+{
+ return IDBKeyRange::create(bound, 0, open, false);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::upperBound(PassRefPtr<IDBKey> bound, bool open)
+{
+ return IDBKeyRange::create(0, bound, false, open);
+}
+
+PassRefPtr<IDBKeyRange> IDBKeyRange::bound(PassRefPtr<IDBKey> lower, PassRefPtr<IDBKey> upper, const OptionsObject& options)
+{
+ bool lowerOpen = false;
+ bool upperOpen = false;
+ options.getKeyBool("lowerOpen", lowerOpen);
+ options.getKeyBool("upperOpen", upperOpen);
+ return IDBKeyRange::create(lower, upper, lowerOpen, upperOpen);
+}
+
+String IDBKeyRange::lowerWhereClauseComparisonOperator() const
+{
+ ASSERT(m_lower);
+ if (m_lowerOpen)
+ return "<";
+ return "<=";
+}
+
+String IDBKeyRange::upperWhereClauseComparisonOperator() const
+{
+ ASSERT(m_upper);
+ if (m_upperOpen)
+ return "<";
+ return "<=";
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBKeyRange.h b/Source/WebCore/storage/IDBKeyRange.h
new file mode 100644
index 0000000..8af48fe
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyRange.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:
+ *
+ * 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 "OptionsObject.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class IDBKeyRange : public ThreadSafeShared<IDBKeyRange> {
+public:
+ static PassRefPtr<IDBKeyRange> create(PassRefPtr<IDBKey> lower, PassRefPtr<IDBKey> upper, bool lowerOpen, bool upperOpen)
+ {
+ return adoptRef(new IDBKeyRange(lower, upper, lowerOpen, upperOpen));
+ }
+ ~IDBKeyRange() { }
+
+
+ PassRefPtr<IDBKey> lower() const { return m_lower; }
+ PassRefPtr<IDBKey> upper() const { return m_upper; }
+ bool lowerOpen() const { return m_lowerOpen; }
+ bool upperOpen() const { return m_upperOpen; }
+
+ String lowerWhereClauseComparisonOperator() const;
+ String upperWhereClauseComparisonOperator() const;
+
+ static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value);
+ static PassRefPtr<IDBKeyRange> lowerBound(PassRefPtr<IDBKey> bound, bool open = false);
+ static PassRefPtr<IDBKeyRange> upperBound(PassRefPtr<IDBKey> bound, bool open = false);
+ static PassRefPtr<IDBKeyRange> bound(PassRefPtr<IDBKey> lower, PassRefPtr<IDBKey> upper, const OptionsObject& = OptionsObject());
+
+private:
+ IDBKeyRange(PassRefPtr<IDBKey> lower, PassRefPtr<IDBKey> upper, bool lowerOpen, bool upperOpen);
+
+ RefPtr<IDBKey> m_lower;
+ RefPtr<IDBKey> m_upper;
+ bool m_lowerOpen;
+ bool m_upperOpen;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBKeyRange_h
diff --git a/Source/WebCore/storage/IDBKeyRange.idl b/Source/WebCore/storage/IDBKeyRange.idl
new file mode 100644
index 0000000..d7fa075
--- /dev/null
+++ b/Source/WebCore/storage/IDBKeyRange.idl
@@ -0,0 +1,43 @@
+/*
+ * 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 {
+ readonly attribute IDBKey lower;
+ readonly attribute IDBKey upper;
+ readonly attribute boolean lowerOpen;
+ readonly attribute boolean upperOpen;
+
+ // FIXME: Make ClassMethod work for JSC as well.
+ [ClassMethod] IDBKeyRange only(in IDBKey value);
+ [ClassMethod] IDBKeyRange lowerBound(in IDBKey bound, in [Optional] boolean open);
+ [ClassMethod] IDBKeyRange upperBound(in IDBKey bound, in [Optional] boolean open);
+ [ClassMethod] IDBKeyRange bound(in IDBKey lower, in IDBKey upper, in [Optional] OptionsObject options);
+ };
+
+}
diff --git a/Source/WebCore/storage/IDBObjectStore.cpp b/Source/WebCore/storage/IDBObjectStore.cpp
new file mode 100644
index 0000000..ed5c96a
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStore.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 "IDBObjectStore.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "DOMStringList.h"
+#include "IDBAny.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndex.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
+#include "IDBTransactionBackendInterface.h"
+#include "SerializedScriptValue.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+static const unsigned short defaultDirection = IDBCursor::NEXT;
+
+IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransactionBackendInterface* transaction)
+ : m_objectStore(idbObjectStore)
+ , m_transaction(transaction)
+{
+ ASSERT(m_objectStore);
+ ASSERT(m_transaction);
+ // We pass a reference to this object before it can be adopted.
+ relaxAdoptionRequirement();
+}
+
+String IDBObjectStore::name() const
+{
+ return m_objectStore->name();
+}
+
+String IDBObjectStore::keyPath() const
+{
+ return m_objectStore->keyPath();
+}
+
+PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
+{
+ return m_objectStore->indexNames();
+}
+
+PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->get(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request.release();
+}
+
+PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->put(value, key, true, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->put(value, key, false, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
+{
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->deleteFunction(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request;
+}
+
+PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, const OptionsObject& options, ExceptionCode& ec)
+{
+ bool unique = false;
+ options.getKeyBool("unique", unique);
+
+ RefPtr<IDBIndexBackendInterface> index = m_objectStore->createIndex(name, keyPath, unique, m_transaction.get(), ec);
+ ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
+ if (!index)
+ return 0;
+ return IDBIndex::create(index.release(), m_transaction.get());
+}
+
+PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendInterface> index = m_objectStore->index(name, ec);
+ ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
+ if (!index)
+ return 0;
+ return IDBIndex::create(index.release(), m_transaction.get());
+}
+
+void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec)
+{
+ m_objectStore->deleteIndex(name, m_transaction.get(), ec);
+}
+
+PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, const OptionsObject& options, ExceptionCode& ec)
+{
+ RefPtr<IDBKeyRange> range = options.getKeyKeyRange("range");
+
+ // Converted to an unsigned short.
+ int32_t direction = defaultDirection;
+ options.getKeyInt32("direction", direction);
+ if (direction != IDBCursor::NEXT && direction != IDBCursor::NEXT_NO_DUPLICATE && direction != IDBCursor::PREV && direction != IDBCursor::PREV_NO_DUPLICATE) {
+ // FIXME: May need to change when specced: http://www.w3.org/Bugs/Public/show_bug.cgi?id=11406
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->openCursor(range, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
+ return request.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBObjectStore.h b/Source/WebCore/storage/IDBObjectStore.h
new file mode 100644
index 0000000..0e9a4a9
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStore.h
@@ -0,0 +1,92 @@
+/*
+ * 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 "IDBCursor.h"
+#include "IDBIndex.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
+#include "IDBObjectStoreBackendInterface.h"
+#include "IDBRequest.h"
+#include "OptionsObject.h"
+#include "PlatformString.h"
+#include "SerializedScriptValue.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+class IDBAny;
+class IDBTransactionBackendInterface;
+
+class IDBObjectStore : public RefCounted<IDBObjectStore> {
+public:
+ static PassRefPtr<IDBObjectStore> create(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransactionBackendInterface* transaction)
+ {
+ return adoptRef(new IDBObjectStore(idbObjectStore, transaction));
+ }
+ ~IDBObjectStore() { }
+
+ String name() const;
+ String keyPath() const;
+ PassRefPtr<DOMStringList> indexNames() const;
+
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBRequest> add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return add(context, value, 0, ec); }
+ PassRefPtr<IDBRequest> put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return put(context, value, 0, ec); }
+ PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, ExceptionCode& ec) { return createIndex(name, keyPath, OptionsObject(), ec); }
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, OptionsObject(), ec); }
+
+ PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> deleteFunction(ScriptExecutionContext*, PassRefPtr<IDBKey> key, ExceptionCode&);
+
+ PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, const OptionsObject&, ExceptionCode&);
+ PassRefPtr<IDBIndex> index(const String& name, ExceptionCode&);
+ void deleteIndex(const String& name, ExceptionCode&);
+
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, const OptionsObject&, ExceptionCode&);
+
+private:
+ IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface>, IDBTransactionBackendInterface* transaction);
+ void removeTransactionFromPendingList();
+
+ RefPtr<IDBObjectStoreBackendInterface> m_objectStore;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStore_h
+
diff --git a/Source/WebCore/storage/IDBObjectStore.idl b/Source/WebCore/storage/IDBObjectStore.idl
new file mode 100644
index 0000000..f023dbe
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStore.idl
@@ -0,0 +1,52 @@
+/*
+ * 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
+ ] IDBObjectStore {
+ readonly attribute DOMString name;
+ readonly attribute [ConvertNullStringTo=Null] DOMString keyPath;
+ readonly attribute DOMStringList indexNames;
+
+ [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext, ImplementationFunction=deleteFunction] IDBRequest delete(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] OptionsObject options)
+ raises (IDBDatabaseException);
+ IDBIndex createIndex(in DOMString name, in [ConvertNullToNullString] DOMString keyPath, in [Optional] OptionsObject options)
+ raises (IDBDatabaseException);
+ IDBIndex index(in DOMString name)
+ raises (IDBDatabaseException);
+ void deleteIndex(in DOMString name)
+ raises (IDBDatabaseException);
+ };
+}
diff --git a/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
new file mode 100644
index 0000000..22d3b8d
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
@@ -0,0 +1,501 @@
+/*
+ * 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 "IDBObjectStoreBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
+#include "DOMStringList.h"
+#include "IDBBindingUtilities.h"
+#include "IDBCallbacks.h"
+#include "IDBCursorBackendImpl.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndexBackendImpl.h"
+#include "IDBKey.h"
+#include "IDBKeyPath.h"
+#include "IDBKeyPathBackendImpl.h"
+#include "IDBKeyRange.h"
+#include "IDBSQLiteDatabase.h"
+#include "IDBTransactionBackendInterface.h"
+#include "ScriptExecutionContext.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+
+namespace WebCore {
+
+IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
+{
+}
+
+IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
+ : m_database(database)
+ , m_id(id)
+ , m_name(name)
+ , m_keyPath(keyPath)
+ , m_autoIncrement(autoIncrement)
+{
+ loadIndexes();
+}
+
+IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBSQLiteDatabase* database, const String& name, const String& keyPath, bool autoIncrement)
+ : m_database(database)
+ , m_id(InvalidId)
+ , m_name(name)
+ , m_keyPath(keyPath)
+ , m_autoIncrement(autoIncrement)
+{
+}
+
+PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::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();
+}
+
+static String whereClause(IDBKey* key)
+{
+ return "WHERE objectStoreId = ? AND " + key->whereSyntax();
+}
+
+static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)
+{
+ query.bindInt64(1, id);
+ key->bind(query, 2);
+}
+
+void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+ SQLiteStatement query(objectStore->sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key.get()));
+ bool ok = query.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ bindWhereClause(query, objectStore->id(), key.get());
+ if (query.step() != SQLResultRow) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
+ return;
+ }
+
+ ASSERT((key->type() == IDBKey::StringType) != query.isColumnNull(0));
+ // FIXME: Implement date.
+ ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2));
+
+ callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(3)));
+ ASSERT(query.step() != SQLResultRow);
+}
+
+static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const String& keyPath)
+{
+ Vector<RefPtr<SerializedScriptValue> > values;
+ values.append(value);
+ Vector<RefPtr<IDBKey> > keys;
+ IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
+ if (keys.isEmpty())
+ return 0;
+ ASSERT(keys.size() == 1);
+ return keys[0].release();
+}
+
+static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t& dataRowId)
+{
+ String sql = dataRowId != IDBObjectStoreBackendImpl::InvalidId ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?"
+ : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)";
+ SQLiteStatement query(db, sql);
+ if (query.prepare() != SQLResultOk)
+ return false;
+ key->bindWithNulls(query, 1);
+ query.bindText(4, value->toWireString());
+ if (dataRowId != IDBDatabaseBackendImpl::InvalidId)
+ query.bindInt64(5, dataRowId);
+ else
+ query.bindInt64(5, objectStoreId);
+
+ if (query.step() != SQLResultDone)
+ return false;
+
+ if (dataRowId == IDBDatabaseBackendImpl::InvalidId)
+ dataRowId = db.lastInsertRowID();
+
+ return true;
+}
+
+static bool deleteIndexData(SQLiteDatabase& db, int64_t objectStoreDataId)
+{
+ SQLiteStatement deleteQuery(db, "DELETE FROM IndexData WHERE objectStoreDataId = ?");
+ if (deleteQuery.prepare() != SQLResultOk)
+ return false;
+ deleteQuery.bindInt64(1, objectStoreDataId);
+
+ return deleteQuery.step() == SQLResultDone;
+}
+
+static bool putIndexData(SQLiteDatabase& db, IDBKey* key, int64_t indexId, int64_t objectStoreDataId)
+{
+ SQLiteStatement putQuery(db, "INSERT INTO IndexData (keyString, keyDate, keyNumber, indexId, objectStoreDataId) VALUES (?, ?, ?, ?, ?)");
+ if (putQuery.prepare() != SQLResultOk)
+ return false;
+ key->bindWithNulls(putQuery, 1);
+ putQuery.bindInt64(4, indexId);
+ putQuery.bindInt64(5, objectStoreDataId);
+
+ return putQuery.step() == SQLResultDone;
+}
+
+void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<SerializedScriptValue> value = prpValue;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ // FIXME: This should throw a SERIAL_ERR on structured clone problems.
+ // FIXME: This should throw a DATA_ERR when the wrong key/keyPath data is supplied.
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, addOnly, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ RefPtr<SerializedScriptValue> value = prpValue;
+ RefPtr<IDBKey> key = prpKey;
+
+ // FIXME: Support auto-increment.
+
+ if (!objectStore->m_keyPath.isNull()) {
+ if (key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath."));
+ return;
+ }
+ key = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
+ if (!key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from the keyPath."));
+ return;
+ }
+ } else if (!key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied."));
+ return;
+ }
+ if (key->type() == IDBKey::NullType) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "NULL key is not allowed."));
+ return;
+ }
+
+ Vector<RefPtr<IDBKey> > indexKeys;
+ for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
+ RefPtr<IDBKey> key = fetchKeyFromKeyPath(value.get(), it->second->keyPath());
+ if (!key) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from an index's keyPath."));
+ return;
+ }
+ if (key->type() == IDBKey::NullType) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index is NULL."));
+ return;
+ }
+ if (!it->second->addingKeyAllowed(key.get())) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
+ return;
+ }
+ indexKeys.append(key.release());
+ }
+
+ SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
+ bool ok = getQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ bindWhereClause(getQuery, objectStore->id(), key.get());
+ bool isExistingValue = getQuery.step() == SQLResultRow;
+ if (addOnly && isExistingValue) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
+ return;
+ }
+
+ // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
+
+ int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId;
+ if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+
+ if (!deleteIndexData(objectStore->sqliteDatabase(), dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+
+ int i = 0;
+ for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
+ if (!putIndexData(objectStore->sqliteDatabase(), indexKeys[i].get(), it->second->id(), dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+ }
+
+ callbacks->onSuccess(key.get());
+}
+
+void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+ SQLiteStatement idQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
+ bool ok = idQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ bindWhereClause(idQuery, objectStore->id(), key.get());
+ if (idQuery.step() != SQLResultRow) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
+ return;
+ }
+
+ int64_t id = idQuery.getColumnInt64(0);
+
+ SQLiteStatement osQuery(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE id = ?");
+ ok = osQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ osQuery.bindInt64(1, id);
+
+ ok = osQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok);
+
+ SQLiteStatement indexQuery(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE objectStoreDataId = ?");
+ ok = indexQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ indexQuery.bindInt64(1, id);
+
+ ok = indexQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok);
+
+ callbacks->onSuccess();
+}
+
+PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ if (m_indexes.contains(name)) {
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+ if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database.get(), name, m_name, keyPath, unique);
+ ASSERT(index->name() == name);
+
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
+ createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ m_indexes.set(name, index);
+ return index.release();
+}
+
+void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ SQLiteStatement insert(objectStore->sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)");
+ if (insert.prepare() != SQLResultOk) {
+ transaction->abort();
+ return;
+ }
+ insert.bindInt64(1, objectStore->m_id);
+ insert.bindText(2, index->name());
+ insert.bindText(3, index->keyPath());
+ insert.bindInt(4, static_cast<int>(index->unique()));
+ if (insert.step() != SQLResultDone) {
+ transaction->abort();
+ return;
+ }
+ int64_t id = objectStore->sqliteDatabase().lastInsertRowID();
+ index->setId(id);
+ transaction->didCompleteTaskEvents();
+}
+
+PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
+ if (!index) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return 0;
+ }
+ return index.release();
+}
+
+static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
+{
+ SQLiteStatement deleteQuery(db, sql);
+ bool ok = deleteQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ deleteQuery.bindInt64(1, id);
+ ok = deleteQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+}
+
+void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
+ if (!index) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return;
+ }
+
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal, objectStore, index, transactionPtr),
+ createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+ m_indexes.remove(name);
+}
+
+void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ doDelete(objectStore->sqliteDatabase(), "DELETE FROM Indexes WHERE id = ?", index->id());
+ doDelete(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId = ?", index->id());
+
+ transaction->didCompleteTaskEvents();
+}
+
+void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKeyRange> range = prpRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ bool lowerBound = range && range->lower();
+ bool upperBound = range && range->upper();
+
+ // Several files depend on this order of selects.
+ String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE ";
+ if (lowerBound)
+ sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator());
+ if (upperBound)
+ sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator());
+ sql += "objectStoreId = ? ORDER BY ";
+
+ IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
+ if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
+ sql += "keyString, keyDate, keyNumber";
+ else
+ sql += "keyString DESC, keyDate DESC, keyNumber DESC";
+
+ OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(objectStore->sqliteDatabase(), sql));
+ bool ok = query->prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ int currentColumn = 1;
+ if (lowerBound)
+ currentColumn += range->lower()->bind(*query, currentColumn);
+ if (upperBound)
+ currentColumn += range->upper()->bind(*query, currentColumn);
+ query->bindInt64(currentColumn, objectStore->id());
+
+ if (query->step() != SQLResultRow) {
+ callbacks->onSuccess();
+ return;
+ }
+
+ RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(objectStore->m_database.get(), range, direction, query.release(), true, transaction.get(), objectStore.get());
+ callbacks->onSuccess(cursor.release());
+}
+
+void IDBObjectStoreBackendImpl::loadIndexes()
+{
+ SQLiteStatement indexQuery(sqliteDatabase(), "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?");
+ bool ok = indexQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+ indexQuery.bindInt64(1, m_id);
+
+ while (indexQuery.step() == SQLResultRow) {
+ int64_t id = indexQuery.getColumnInt64(0);
+ String name = indexQuery.getColumnText(1);
+ String keyPath = indexQuery.getColumnText(2);
+ bool unique = !!indexQuery.getColumnInt(3);
+
+ m_indexes.set(name, IDBIndexBackendImpl::create(m_database.get(), id, name, m_name, keyPath, unique));
+ }
+}
+
+SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const
+{
+ return m_database->db();
+}
+
+void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
+{
+ ASSERT(objectStore->m_indexes.contains(index->name()));
+ objectStore->m_indexes.remove(index->name());
+}
+
+void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
+{
+ RefPtr<IDBIndexBackendImpl> indexPtr = index;
+ ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
+ objectStore->m_indexes.set(indexPtr->name(), indexPtr);
+}
+
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBObjectStoreBackendImpl.h b/Source/WebCore/storage/IDBObjectStoreBackendImpl.h
new file mode 100644
index 0000000..2ab42f2
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStoreBackendImpl.h
@@ -0,0 +1,112 @@
+/*
+ * 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 IDBObjectStoreBackendImpl_h
+#define IDBObjectStoreBackendImpl_h
+
+#include "IDBObjectStoreBackendInterface.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBDatabaseBackendImpl;
+class IDBIndexBackendImpl;
+class IDBSQLiteDatabase;
+class IDBTransactionBackendInterface;
+class SQLiteDatabase;
+class ScriptExecutionContext;
+
+class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface {
+public:
+ static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBSQLiteDatabase* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
+ {
+ return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement));
+ }
+ static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBSQLiteDatabase* database, const String& name, const String& keyPath, bool autoIncrement)
+ {
+ return adoptRef(new IDBObjectStoreBackendImpl(database, name, keyPath, autoIncrement));
+ }
+ virtual ~IDBObjectStoreBackendImpl();
+
+ static const int64_t InvalidId = 0;
+ int64_t id() const
+ {
+ ASSERT(m_id != InvalidId);
+ return m_id;
+ }
+ void setId(int64_t id) { m_id = id; }
+
+ virtual String name() const { return m_name; }
+ virtual String keyPath() const { return m_keyPath; }
+ virtual PassRefPtr<DOMStringList> indexNames() const;
+ virtual bool autoIncrement() const { return m_autoIncrement; }
+
+ virtual void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void deleteFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+
+ virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&);
+ virtual void deleteIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&);
+
+ virtual void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+
+private:
+ IDBObjectStoreBackendImpl(IDBSQLiteDatabase*, int64_t id, const String& name, const String& keyPath, bool autoIncrement);
+ IDBObjectStoreBackendImpl(IDBSQLiteDatabase*, const String& name, const String& keyPath, bool autoIncrement);
+
+ void loadIndexes();
+ SQLiteDatabase& sqliteDatabase() const;
+
+ static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ static void putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ static void createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+
+ // These are used as setVersion transaction abort tasks.
+ static void removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
+ static void addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
+
+ RefPtr<IDBSQLiteDatabase> m_database;
+
+ int64_t m_id;
+ String m_name;
+ String m_keyPath;
+ bool m_autoIncrement;
+
+ typedef HashMap<String, RefPtr<IDBIndexBackendImpl> > IndexMap;
+ IndexMap m_indexes;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStoreBackendImpl_h
diff --git a/Source/WebCore/storage/IDBObjectStoreBackendInterface.h b/Source/WebCore/storage/IDBObjectStoreBackendInterface.h
new file mode 100644
index 0000000..02ceb27
--- /dev/null
+++ b/Source/WebCore/storage/IDBObjectStoreBackendInterface.h
@@ -0,0 +1,69 @@
+/*
+ * 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 IDBObjectStoreBackendInterface_h
+#define IDBObjectStoreBackendInterface_h
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class DOMStringList;
+class IDBCallbacks;
+class IDBIndexBackendInterface;
+class IDBKey;
+class IDBKeyRange;
+class IDBTransactionBackendInterface;
+class SerializedScriptValue;
+
+class IDBObjectStoreBackendInterface : public ThreadSafeShared<IDBObjectStoreBackendInterface> {
+public:
+ virtual ~IDBObjectStoreBackendInterface() { }
+
+ virtual String name() const = 0;
+ virtual String keyPath() const = 0;
+ virtual PassRefPtr<DOMStringList> indexNames() const = 0;
+
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void put(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, bool addOnly, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void deleteFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+
+ virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&) = 0;
+ virtual void deleteIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBObjectStoreBackendInterface_h
+
diff --git a/Source/WebCore/storage/IDBPendingTransactionMonitor.cpp b/Source/WebCore/storage/IDBPendingTransactionMonitor.cpp
new file mode 100644
index 0000000..799200d
--- /dev/null
+++ b/Source/WebCore/storage/IDBPendingTransactionMonitor.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 "IDBPendingTransactionMonitor.h"
+#include "IDBTransactionBackendInterface.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+Vector<IDBTransactionBackendInterface*>* IDBPendingTransactionMonitor::m_transactions = 0;
+
+void IDBPendingTransactionMonitor::addPendingTransaction(IDBTransactionBackendInterface* transaction)
+{
+ if (!m_transactions)
+ m_transactions = new Vector<IDBTransactionBackendInterface*>();
+ m_transactions->append(transaction);
+}
+
+void IDBPendingTransactionMonitor::removePendingTransaction(IDBTransactionBackendInterface* transaction)
+{
+ if (!m_transactions)
+ return;
+
+ size_t pos = m_transactions->find(transaction);
+ if (pos == notFound)
+ return;
+
+ m_transactions->remove(pos);
+
+ if (!m_transactions->size()) {
+ delete m_transactions;
+ m_transactions = 0;
+ }
+}
+
+void IDBPendingTransactionMonitor::abortPendingTransactions()
+{
+ if (!m_transactions)
+ return;
+
+ for (size_t i = 0; i < m_transactions->size(); ++i)
+ m_transactions->at(i)->abort();
+
+ delete m_transactions;
+ m_transactions = 0;
+}
+
+};
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBPendingTransactionMonitor.h b/Source/WebCore/storage/IDBPendingTransactionMonitor.h
new file mode 100644
index 0000000..783a731
--- /dev/null
+++ b/Source/WebCore/storage/IDBPendingTransactionMonitor.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:
+ *
+ * 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 IDBPendingTransactionMonitor_h
+#define IDBPendingTransactionMonitor_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class IDBTransactionBackendInterface;
+
+// This class keeps track of the transactions created during the current
+// Javascript execution context. A transaction is 'pending' if no asynchronous
+// operation is currently queued for it (e.g. an IDBObjectStore::put() or similar).
+// All pending transactions are aborted as soon as execution returns from
+// the script engine.
+//
+// FIXME: move the vector of transactions to TLS. Keeping it static
+// will not work once we add support for workers. Another possible
+// solution is to keep the vector in the ScriptExecutionContext.
+class IDBPendingTransactionMonitor : public Noncopyable {
+public:
+ static void addPendingTransaction(IDBTransactionBackendInterface*);
+ static void removePendingTransaction(IDBTransactionBackendInterface*);
+ static void abortPendingTransactions();
+
+private:
+ IDBPendingTransactionMonitor();
+
+ static Vector<IDBTransactionBackendInterface*>* m_transactions;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBPendingTransactionMonitor_h
diff --git a/Source/WebCore/storage/IDBRequest.cpp b/Source/WebCore/storage/IDBRequest.cpp
new file mode 100644
index 0000000..cbd635c
--- /dev/null
+++ b/Source/WebCore/storage/IDBRequest.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:
+ *
+ * 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 "IDBRequest.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "Event.h"
+#include "EventException.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "IDBCursor.h"
+#include "IDBDatabase.h"
+#include "IDBIndex.h"
+#include "IDBErrorEvent.h"
+#include "IDBObjectStore.h"
+#include "IDBPendingTransactionMonitor.h"
+#include "IDBSuccessEvent.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction)
+ : ActiveDOMObject(context, this)
+ , m_source(source)
+ , m_transaction(transaction)
+ , m_timer(this, &IDBRequest::timerFired)
+ , m_readyState(LOADING)
+{
+ if (m_transaction)
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
+}
+
+IDBRequest::~IDBRequest()
+{
+}
+
+bool IDBRequest::resetReadyState(IDBTransactionBackendInterface* transaction)
+{
+ ASSERT(m_readyState == DONE);
+ m_readyState = LOADING;
+ ASSERT(!m_transaction);
+ m_transaction = transaction;
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
+ return true;
+}
+
+void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
+{
+ scheduleEvent(0, error);
+}
+
+void IDBRequest::onSuccess()
+{
+ scheduleEvent(IDBAny::createNull(), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
+{
+ scheduleEvent(IDBAny::create(IDBCursor::create(backend, this, m_transaction.get())), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
+{
+ scheduleEvent(IDBAny::create(IDBDatabase::create(backend)), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend)
+{
+ scheduleEvent(IDBAny::create(IDBIndex::create(backend, m_transaction.get())), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
+{
+ scheduleEvent(IDBAny::create(idbKey), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend)
+{
+ // FIXME: This function should go away once createObjectStore is sync.
+ scheduleEvent(IDBAny::create(IDBObjectStore::create(backend, m_transaction.get())), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
+{
+ RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
+ // This is only used by setVersion which will always have a source that's an IDBDatabase.
+ m_source->idbDatabase()->setSetVersionTransaction(backend.get());
+ RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, m_source->idbDatabase().get());
+ backend->setCallbacks(frontend.get());
+ m_transaction = backend;
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
+ scheduleEvent(IDBAny::create(frontend.release()), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
+{
+ scheduleEvent(IDBAny::create(serializedScriptValue), 0);
+}
+
+ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
+}
+
+bool IDBRequest::canSuspend() const
+{
+ // IDBTransactions cannot be suspended at the moment. We therefore
+ // disallow the back/forward cache for pages that use IndexedDatabase.
+ return false;
+}
+
+EventTargetData* IDBRequest::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* IDBRequest::ensureEventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+void IDBRequest::timerFired(Timer<IDBRequest>*)
+{
+ ASSERT(m_selfRef);
+ ASSERT(m_pendingEvents.size());
+ // FIXME: We should handle the stop event and stop any timers when we see it. We can then assert here that scriptExecutionContext is non-null.
+
+ // 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();
+
+ // readyStateReset can be called synchronously while we're dispatching the event.
+ RefPtr<IDBTransactionBackendInterface> transaction = m_transaction;
+ m_transaction.clear();
+
+ Vector<PendingEvent> pendingEvents;
+ pendingEvents.swap(m_pendingEvents);
+ for (size_t i = 0; i < pendingEvents.size(); ++i) {
+ // It's possible we've navigated in which case we'll crash.
+ if (!scriptExecutionContext())
+ return;
+
+ if (pendingEvents[i].m_error) {
+ ASSERT(!pendingEvents[i].m_result);
+ dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvents[i].m_error));
+ } else {
+ ASSERT(pendingEvents[i].m_result->type() != IDBAny::UndefinedType);
+ dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvents[i].m_result));
+ }
+ }
+ if (transaction) {
+ // Now that we processed all pending events, let the transaction monitor check if
+ // it can commit the current transaction or if there's anything new pending.
+ // FIXME: Handle the workers case.
+ transaction->didCompleteTaskEvents();
+ }
+}
+
+void IDBRequest::scheduleEvent(PassRefPtr<IDBAny> result, PassRefPtr<IDBDatabaseError> error)
+{
+ ASSERT(m_readyState < DONE);
+ ASSERT(!!m_selfRef == m_timer.isActive());
+
+ PendingEvent pendingEvent;
+ pendingEvent.m_result = result;
+ pendingEvent.m_error = error;
+ m_pendingEvents.append(pendingEvent);
+
+ m_readyState = DONE;
+ if (!m_timer.isActive()) {
+ m_selfRef = this;
+ m_timer.startOneShot(0);
+ }
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBRequest.h b/Source/WebCore/storage/IDBRequest.h
new file mode 100644
index 0000000..fa68208
--- /dev/null
+++ b/Source/WebCore/storage/IDBRequest.h
@@ -0,0 +1,117 @@
+/*
+ * 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 IDBRequest_h
+#define IDBRequest_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ActiveDOMObject.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "EventTarget.h"
+#include "IDBAny.h"
+#include "IDBCallbacks.h"
+#include "Timer.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class IDBTransactionBackendInterface;
+
+class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
+public:
+ static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction) { return adoptRef(new IDBRequest(context, source, transaction)); }
+ virtual ~IDBRequest();
+
+ // Defined in the IDL
+ enum ReadyState {
+ LOADING = 1,
+ DONE = 2
+ };
+ unsigned short readyState() const { return m_readyState; }
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(success);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
+
+ bool resetReadyState(IDBTransactionBackendInterface*);
+
+ // IDBCallbacks
+ virtual void onError(PassRefPtr<IDBDatabaseError>);
+ virtual void onSuccess(); // For "null".
+ virtual void onSuccess(PassRefPtr<IDBDatabaseBackendInterface>);
+ virtual void onSuccess(PassRefPtr<IDBCursorBackendInterface>);
+ virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>);
+ virtual void onSuccess(PassRefPtr<IDBKey>);
+ virtual void onSuccess(PassRefPtr<IDBObjectStoreBackendInterface>);
+ virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>);
+ virtual void onSuccess(PassRefPtr<SerializedScriptValue>);
+
+ // EventTarget
+ virtual IDBRequest* toIDBRequest() { return this; }
+
+ // ActiveDOMObject
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+ virtual bool canSuspend() const;
+
+ using ThreadSafeShared<IDBCallbacks>::ref;
+ using ThreadSafeShared<IDBCallbacks>::deref;
+
+private:
+ IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction);
+
+ void timerFired(Timer<IDBRequest>*);
+ void scheduleEvent(PassRefPtr<IDBAny> result, PassRefPtr<IDBDatabaseError>);
+
+ // EventTarget
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ RefPtr<IDBAny> m_source;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
+
+ struct PendingEvent {
+ RefPtr<IDBAny> m_result;
+ RefPtr<IDBDatabaseError> m_error;
+ };
+ Vector<PendingEvent> m_pendingEvents;
+
+ // Used to fire events asynchronously.
+ Timer<IDBRequest> m_timer;
+ RefPtr<IDBRequest> m_selfRef; // This is set to us iff there's an event pending.
+
+ ReadyState m_readyState;
+ EventTargetData m_eventTargetData;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBRequest_h
diff --git a/Source/WebCore/storage/IDBRequest.idl b/Source/WebCore/storage/IDBRequest.idl
new file mode 100644
index 0000000..58872f0
--- /dev/null
+++ b/Source/WebCore/storage/IDBRequest.idl
@@ -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.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE,
+ EventTarget
+ ] IDBRequest {
+
+ // States
+ const unsigned short LOADING = 1;
+ const unsigned short DONE = 2;
+ readonly attribute unsigned short readyState;
+
+ // 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/Source/WebCore/storage/IDBSQLiteDatabase.cpp b/Source/WebCore/storage/IDBSQLiteDatabase.cpp
new file mode 100644
index 0000000..e881917
--- /dev/null
+++ b/Source/WebCore/storage/IDBSQLiteDatabase.cpp
@@ -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.
+ */
+
+#include "config.h"
+#include "IDBSQLiteDatabase.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBFactoryBackendImpl.h"
+
+namespace WebCore {
+
+IDBSQLiteDatabase::IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory)
+ : m_identifier(identifier)
+ , m_factory(factory)
+{
+}
+
+IDBSQLiteDatabase::~IDBSQLiteDatabase()
+{
+ m_factory->removeSQLiteDatabase(m_identifier);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBSQLiteDatabase.h b/Source/WebCore/storage/IDBSQLiteDatabase.h
new file mode 100644
index 0000000..0556506
--- /dev/null
+++ b/Source/WebCore/storage/IDBSQLiteDatabase.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 IDBSQLiteDatabase_h
+#define IDBSQLiteDatabase_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "SQLiteDatabase.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBFactoryBackendImpl;
+
+class IDBSQLiteDatabase : public RefCounted<IDBSQLiteDatabase> {
+public:
+ static PassRefPtr<IDBSQLiteDatabase> create(String identifier, IDBFactoryBackendImpl* factory)
+ {
+ return adoptRef(new IDBSQLiteDatabase(identifier, factory));
+ }
+ ~IDBSQLiteDatabase();
+
+ SQLiteDatabase& db() { return m_db; }
+
+private:
+ IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory);
+
+ SQLiteDatabase m_db;
+ String m_identifier;
+ RefPtr<IDBFactoryBackendImpl> m_factory;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBSQLiteDatabase_h
diff --git a/Source/WebCore/storage/IDBSuccessEvent.cpp b/Source/WebCore/storage/IDBSuccessEvent.cpp
new file mode 100644
index 0000000..2dcd964
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBSuccessEvent.h b/Source/WebCore/storage/IDBSuccessEvent.h
new file mode 100644
index 0000000..5be660a
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBSuccessEvent.idl b/Source/WebCore/storage/IDBSuccessEvent.idl
new file mode 100644
index 0000000..b4ea7d2
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/IDBTimeoutEvent.cpp b/Source/WebCore/storage/IDBTimeoutEvent.cpp
new file mode 100644
index 0000000..b61ee47
--- /dev/null
+++ b/Source/WebCore/storage/IDBTimeoutEvent.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 "IDBTimeoutEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBTimeoutEvent> IDBTimeoutEvent::create()
+{
+ return adoptRef(new IDBTimeoutEvent());
+}
+
+IDBTimeoutEvent::IDBTimeoutEvent()
+ : IDBEvent(eventNames().abortEvent, 0) // FIXME: set the source to the transaction
+{
+}
+
+IDBTimeoutEvent::~IDBTimeoutEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/IDBTimeoutEvent.h b/Source/WebCore/storage/IDBTimeoutEvent.h
new file mode 100644
index 0000000..afc9ba4
--- /dev/null
+++ b/Source/WebCore/storage/IDBTimeoutEvent.h
@@ -0,0 +1,57 @@
+/*
+ * 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 IDBTimeoutEvent_h
+#define IDBTimeoutEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBTimeoutEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBTimeoutEvent> create();
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBTimeoutEvent();
+
+ virtual bool isIDBTimeoutEvent() const { return true; }
+
+private:
+ IDBTimeoutEvent();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBTimeoutEvent_h
diff --git a/Source/WebCore/storage/IDBTransaction.cpp b/Source/WebCore/storage/IDBTransaction.cpp
new file mode 100644
index 0000000..e3625d4
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransaction.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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 "IDBTransaction.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "Event.h"
+#include "EventException.h"
+#include "IDBAbortEvent.h"
+#include "IDBCompleteEvent.h"
+#include "IDBDatabase.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndex.h"
+#include "IDBObjectStore.h"
+#include "IDBObjectStoreBackendInterface.h"
+#include "IDBPendingTransactionMonitor.h"
+#include "IDBTimeoutEvent.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
+ : ActiveDOMObject(context, this)
+ , m_backend(backend)
+ , m_database(db)
+ , m_mode(m_backend->mode())
+ , m_onAbortTimer(this, &IDBTransaction::onAbortTimerFired)
+ , m_onCompleteTimer(this, &IDBTransaction::onCompleteTimerFired)
+ , m_onTimeoutTimer(this, &IDBTransaction::onTimeoutTimerFired)
+{
+ IDBPendingTransactionMonitor::addPendingTransaction(m_backend.get());
+}
+
+IDBTransaction::~IDBTransaction()
+{
+}
+
+unsigned short IDBTransaction::mode() const
+{
+ return m_mode;
+}
+
+IDBDatabase* IDBTransaction::db()
+{
+ return m_database.get();
+}
+
+PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, ExceptionCode& ec)
+{
+ if (!m_backend) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+ RefPtr<IDBObjectStoreBackendInterface> objectStoreBackend = m_backend->objectStore(name, ec);
+ if (!objectStoreBackend) {
+ ASSERT(ec);
+ return 0;
+ }
+ RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, m_backend.get());
+ return objectStore.release();
+}
+
+void IDBTransaction::abort()
+{
+ if (m_backend)
+ m_backend->abort();
+}
+
+ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
+}
+
+void IDBTransaction::onAbort()
+{
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onAbortTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+}
+
+void IDBTransaction::onComplete()
+{
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onCompleteTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+}
+
+void IDBTransaction::onTimeout()
+{
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onTimeoutTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+}
+
+bool IDBTransaction::canSuspend() const
+{
+ // We may be in the middle of a transaction so we cannot suspend our object.
+ // Instead, we simply don't allow the owner page to go into the back/forward cache.
+ return false;
+}
+
+void IDBTransaction::stop()
+{
+ if (m_backend)
+ m_backend->abort();
+}
+
+EventTargetData* IDBTransaction::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* IDBTransaction::ensureEventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+void IDBTransaction::onAbortTimerFired(Timer<IDBTransaction>* transaction)
+{
+ ASSERT(m_selfRef);
+ RefPtr<IDBTransaction> selfRef = m_selfRef.release();
+ dispatchEvent(IDBAbortEvent::create());
+}
+
+void IDBTransaction::onCompleteTimerFired(Timer<IDBTransaction>* transaction)
+{
+ ASSERT(m_selfRef);
+ RefPtr<IDBTransaction> selfRef = m_selfRef.release();
+ dispatchEvent(IDBCompleteEvent::create());
+}
+
+
+void IDBTransaction::onTimeoutTimerFired(Timer<IDBTransaction>* transaction)
+{
+ ASSERT(m_selfRef);
+ RefPtr<IDBTransaction> selfRef = m_selfRef.release();
+ dispatchEvent(IDBTimeoutEvent::create());
+}
+
+}
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBTransaction.h b/Source/WebCore/storage/IDBTransaction.h
new file mode 100644
index 0000000..d0a9f0f
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransaction.h
@@ -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.
+ */
+
+#ifndef IDBTransaction_h
+#define IDBTransaction_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ActiveDOMObject.h"
+#include "DOMStringList.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "EventTarget.h"
+#include "IDBTransactionBackendInterface.h"
+#include "IDBTransactionCallbacks.h"
+#include "Timer.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class IDBDatabase;
+class IDBObjectStore;
+
+class IDBTransaction : public IDBTransactionCallbacks, public EventTarget, public ActiveDOMObject {
+public:
+ static PassRefPtr<IDBTransaction> create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
+ {
+ return adoptRef(new IDBTransaction(context, backend, db));
+ }
+ virtual ~IDBTransaction();
+
+ enum Mode {
+ READ_WRITE = 0,
+ READ_ONLY = 1,
+ VERSION_CHANGE = 2
+ };
+
+ unsigned short mode() const;
+ IDBDatabase* db();
+ PassRefPtr<IDBObjectStore> objectStore(const String& name, ExceptionCode&);
+ void abort();
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(complete);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(timeout);
+
+ // IDBTransactionCallbacks
+ virtual void onAbort();
+ virtual void onComplete();
+ virtual void onTimeout();
+
+ // EventTarget
+ virtual IDBTransaction* toIDBTransaction() { return this; }
+
+ // ActiveDOMObject
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+ virtual bool canSuspend() const;
+ virtual void stop();
+
+ using RefCounted<IDBTransactionCallbacks>::ref;
+ using RefCounted<IDBTransactionCallbacks>::deref;
+
+private:
+ IDBTransaction(ScriptExecutionContext*, PassRefPtr<IDBTransactionBackendInterface>, IDBDatabase*);
+
+ // EventTarget
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ void onAbortTimerFired(Timer<IDBTransaction>*);
+ void onCompleteTimerFired(Timer<IDBTransaction>*);
+ void onTimeoutTimerFired(Timer<IDBTransaction>*);
+
+ EventTargetData m_eventTargetData;
+ RefPtr<IDBTransactionBackendInterface> m_backend;
+ RefPtr<IDBDatabase> m_database;
+ unsigned short m_mode;
+
+ Timer<IDBTransaction> m_onAbortTimer;
+ Timer<IDBTransaction> m_onCompleteTimer;
+ Timer<IDBTransaction> m_onTimeoutTimer;
+ RefPtr<IDBTransaction> m_selfRef; // This is set to us iff there's an event pending.
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBTransaction_h
diff --git a/Source/WebCore/storage/IDBTransaction.idl b/Source/WebCore/storage/IDBTransaction.idl
new file mode 100644
index 0000000..b57ac4a
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransaction.idl
@@ -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.
+ */
+
+module storage {
+
+ interface [
+ Conditional=INDEXED_DATABASE,
+ EventTarget
+ ] IDBTransaction {
+ // Modes
+ const unsigned short READ_WRITE = 0;
+ const unsigned short READ_ONLY = 1;
+ const unsigned short VERSION_CHANGE = 2;
+
+ // Properties
+ readonly attribute unsigned short mode;
+ readonly attribute IDBDatabase db;
+ // Methods
+ IDBObjectStore objectStore (in DOMString name)
+ raises (IDBDatabaseException);
+ void abort ();
+ // Events
+ attribute EventListener onabort;
+ attribute EventListener oncomplete;
+ attribute EventListener ontimeout;
+ // 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/Source/WebCore/storage/IDBTransactionBackendImpl.cpp b/Source/WebCore/storage/IDBTransactionBackendImpl.cpp
new file mode 100644
index 0000000..0012231
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionBackendImpl.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "IDBTransactionBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseException.h"
+#include "IDBTransactionCoordinator.h"
+#include "SQLiteDatabase.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBTransactionBackendImpl> IDBTransactionBackendImpl::create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl* database)
+{
+ return adoptRef(new IDBTransactionBackendImpl(objectStores, mode, timeout, database));
+}
+
+IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl* database)
+ : m_objectStoreNames(objectStores)
+ , m_mode(mode)
+ , m_timeout(timeout) // FIXME: Implement timeout.
+ , m_state(Unused)
+ , m_database(database)
+ , m_transaction(new SQLiteTransaction(database->sqliteDatabase()))
+ , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired)
+ , m_taskEventTimer(this, &IDBTransactionBackendImpl::taskEventTimerFired)
+ , m_pendingEvents(0)
+{
+ ASSERT(m_objectStoreNames);
+ m_database->transactionCoordinator()->didCreateTransaction(this);
+}
+
+IDBTransactionBackendImpl::~IDBTransactionBackendImpl()
+{
+ // It shouldn't be possible for this object to get deleted until it's either complete or aborted.
+ ASSERT(m_state == Finished);
+}
+
+PassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStore(const String& name, ExceptionCode& ec)
+{
+ if (m_state == Finished) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ // Does a linear search, but it really shouldn't be that slow in practice.
+ if (!m_objectStoreNames->isEmpty() && !m_objectStoreNames->contains(name)) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBObjectStoreBackendInterface> objectStore = m_database->objectStore(name);
+ // FIXME: This is only necessary right now beacuse a setVersion transaction could modify things
+ // between its creation (where another check occurs) and the .objectStore call.
+ // There's a bug to make this impossible in the spec. When we make it impossible here, we
+ // can remove this check.
+ if (!objectStore) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return 0;
+ }
+ return objectStore.release();
+}
+
+bool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask)
+{
+ if (m_state == Finished)
+ return false;
+
+ m_taskQueue.append(task);
+ if (abortTask)
+ m_abortTaskQueue.prepend(abortTask);
+
+ if (m_state == Unused)
+ start();
+
+ return true;
+}
+
+void IDBTransactionBackendImpl::abort()
+{
+ if (m_state == Finished)
+ return;
+
+ // The last reference to this object may be released while performing the
+ // abort steps below. We therefore take a self reference to keep ourselves
+ // alive while executing this method.
+ RefPtr<IDBTransactionBackendImpl> self(this);
+
+ m_state = Finished;
+ m_taskTimer.stop();
+ m_taskEventTimer.stop();
+ m_transaction->rollback();
+
+ // Run the abort tasks, if any.
+ while (!m_abortTaskQueue.isEmpty()) {
+ OwnPtr<ScriptExecutionContext::Task> task(m_abortTaskQueue.first().release());
+ m_abortTaskQueue.removeFirst();
+ task->performTask(0);
+ }
+
+ m_callbacks->onAbort();
+ m_database->transactionCoordinator()->didFinishTransaction(this);
+ ASSERT(!m_database->transactionCoordinator()->isActive(this));
+ m_database = 0;
+}
+
+void IDBTransactionBackendImpl::didCompleteTaskEvents()
+{
+ if (m_state == Finished)
+ return;
+
+ ASSERT(m_state == Running);
+ ASSERT(m_pendingEvents);
+ m_pendingEvents--;
+
+ if (!m_taskEventTimer.isActive())
+ m_taskEventTimer.startOneShot(0);
+}
+
+void IDBTransactionBackendImpl::run()
+{
+ ASSERT(m_state == StartPending || m_state == Running);
+ ASSERT(!m_taskTimer.isActive());
+
+ m_taskTimer.startOneShot(0);
+}
+
+void IDBTransactionBackendImpl::start()
+{
+ ASSERT(m_state == Unused);
+
+ m_state = StartPending;
+ m_database->transactionCoordinator()->didStartTransaction(this);
+}
+
+void IDBTransactionBackendImpl::commit()
+{
+ // The last reference to this object may be released while performing the
+ // commit steps below. We therefore take a self reference to keep ourselves
+ // alive while executing this method.
+ RefPtr<IDBTransactionBackendImpl> self(this);
+ ASSERT(m_state == Running);
+
+ m_state = Finished;
+ m_transaction->commit();
+ m_callbacks->onComplete();
+ m_database->transactionCoordinator()->didFinishTransaction(this);
+ m_database = 0;
+}
+
+void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*)
+{
+ ASSERT(!m_taskQueue.isEmpty());
+
+ if (m_state == StartPending) {
+ m_transaction->begin();
+ m_state = Running;
+ } else
+ ASSERT(m_state == Running);
+
+ TaskQueue queue;
+ queue.swap(m_taskQueue);
+ while (!queue.isEmpty() && m_state != Finished) {
+ OwnPtr<ScriptExecutionContext::Task> task(queue.first().release());
+ queue.removeFirst();
+ m_pendingEvents++;
+ task->performTask(0);
+ }
+}
+
+void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendImpl>*)
+{
+ ASSERT(m_state == Running);
+
+ if (!m_pendingEvents && m_taskQueue.isEmpty()) {
+ // The last task event has completed and the task
+ // queue is empty. Commit the transaction.
+ commit();
+ return;
+ }
+
+ // We are still waiting for other events to complete. However,
+ // the task queue is non-empty and the timer is inactive.
+ // We can therfore schedule the timer again.
+ if (!m_taskQueue.isEmpty() && !m_taskTimer.isActive())
+ m_taskTimer.startOneShot(0);
+}
+
+};
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBTransactionBackendImpl.h b/Source/WebCore/storage/IDBTransactionBackendImpl.h
new file mode 100644
index 0000000..f4dfaa8
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionBackendImpl.h
@@ -0,0 +1,97 @@
+/*
+ * 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 IDBTransactionBackendImpl_h
+#define IDBTransactionBackendImpl_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "DOMStringList.h"
+#include "IDBTransactionBackendInterface.h"
+#include "IDBTransactionCallbacks.h"
+#include "SQLiteTransaction.h"
+#include "Timer.h"
+#include <wtf/Deque.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBDatabaseBackendImpl;
+
+class IDBTransactionBackendImpl : public IDBTransactionBackendInterface {
+public:
+ static PassRefPtr<IDBTransactionBackendImpl> create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl*);
+ virtual ~IDBTransactionBackendImpl();
+
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, ExceptionCode&);
+ virtual unsigned short mode() const { return m_mode; }
+ virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask);
+ virtual void didCompleteTaskEvents();
+ virtual void abort();
+ virtual void setCallbacks(IDBTransactionCallbacks* callbacks) { m_callbacks = callbacks; }
+
+ void run();
+
+private:
+ IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl*);
+
+ enum State {
+ Unused, // Created, but no tasks yet.
+ StartPending, // Enqueued tasks, but SQLite transaction not yet started.
+ Running, // SQLite transaction started but not yet finished.
+ Finished, // Either aborted or committed.
+ };
+
+ void start();
+ void commit();
+
+ void taskTimerFired(Timer<IDBTransactionBackendImpl>*);
+ void taskEventTimerFired(Timer<IDBTransactionBackendImpl>*);
+
+ RefPtr<DOMStringList> m_objectStoreNames;
+ unsigned short m_mode;
+ unsigned long m_timeout;
+
+ State m_state;
+ RefPtr<IDBTransactionCallbacks> m_callbacks;
+ RefPtr<IDBDatabaseBackendImpl> m_database;
+
+ typedef Deque<OwnPtr<ScriptExecutionContext::Task> > TaskQueue;
+ TaskQueue m_taskQueue;
+ TaskQueue m_abortTaskQueue;
+
+ OwnPtr<SQLiteTransaction> m_transaction;
+
+ // FIXME: delete the timer once we have threads instead.
+ Timer<IDBTransactionBackendImpl> m_taskTimer;
+ Timer<IDBTransactionBackendImpl> m_taskEventTimer;
+ int m_pendingEvents;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBTransactionBackendImpl_h
diff --git a/Source/WebCore/storage/IDBTransactionBackendInterface.h b/Source/WebCore/storage/IDBTransactionBackendInterface.h
new file mode 100644
index 0000000..9b1fce6
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionBackendInterface.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 IDBTransactionBackendInterface_h
+#define IDBTransactionBackendInterface_h
+
+#include "ExceptionCode.h"
+#include "IDBCallbacks.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include <wtf/Threading.h>
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+class IDBObjectStoreBackendInterface;
+class IDBTransactionCallbacks;
+class SQLiteDatabase;
+
+// This class is shared by IDBTransaction (async) and IDBTransactionSync (sync).
+// This is implemented by IDBTransactionBackendImpl 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 IDBTransactionBackendInterface : public ThreadSafeShared<IDBTransactionBackendInterface> {
+public:
+ virtual ~IDBTransactionBackendInterface() { }
+
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, ExceptionCode&) = 0;
+ virtual unsigned short mode() const = 0;
+ virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask = 0) = 0;
+ virtual void didCompleteTaskEvents() = 0;
+ virtual void abort() = 0;
+ virtual void setCallbacks(IDBTransactionCallbacks*) = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBTransactionBackendInterface_h
+
diff --git a/Source/WebCore/storage/IDBTransactionCallbacks.h b/Source/WebCore/storage/IDBTransactionCallbacks.h
new file mode 100644
index 0000000..348608d
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionCallbacks.h
@@ -0,0 +1,52 @@
+/*
+ * 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 IDBTransactionCallbacks_h
+#define IDBTransactionCallbacks_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "SerializedScriptValue.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class IDBTransactionCallbacks : public RefCounted<IDBTransactionCallbacks> {
+public:
+ virtual ~IDBTransactionCallbacks() { }
+
+ virtual void onAbort() = 0;
+ virtual void onComplete() = 0;
+ virtual void onTimeout() = 0;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBTransactionCallbacks_h
diff --git a/Source/WebCore/storage/IDBTransactionCoordinator.cpp b/Source/WebCore/storage/IDBTransactionCoordinator.cpp
new file mode 100644
index 0000000..f867f42
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionCoordinator.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "IDBTransactionCoordinator.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBObjectStoreBackendInterface.h"
+#include "IDBTransactionBackendImpl.h"
+#include "SQLiteDatabase.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBTransactionCoordinator> IDBTransactionCoordinator::create()
+{
+ return adoptRef(new IDBTransactionCoordinator());
+}
+
+IDBTransactionCoordinator::IDBTransactionCoordinator()
+{
+}
+
+IDBTransactionCoordinator::~IDBTransactionCoordinator()
+{
+}
+
+void IDBTransactionCoordinator::didCreateTransaction(IDBTransactionBackendImpl* transaction)
+{
+ ASSERT(!m_transactions.contains(transaction));
+ m_transactions.add(transaction, transaction);
+}
+
+void IDBTransactionCoordinator::didStartTransaction(IDBTransactionBackendImpl* transaction)
+{
+ ASSERT(m_transactions.contains(transaction));
+
+ m_startedTransactions.add(transaction);
+ processStartedTransactions();
+}
+
+void IDBTransactionCoordinator::didFinishTransaction(IDBTransactionBackendImpl* transaction)
+{
+ ASSERT(m_transactions.contains(transaction));
+
+ if (m_startedTransactions.contains(transaction)) {
+ ASSERT(!m_runningTransactions.contains(transaction));
+ m_startedTransactions.remove(transaction);
+ } else if (m_runningTransactions.contains(transaction))
+ m_runningTransactions.remove(transaction);
+
+ m_transactions.remove(transaction);
+
+ processStartedTransactions();
+}
+
+#ifndef NDEBUG
+// Verifies internal consistiency while returning whether anything is found.
+bool IDBTransactionCoordinator::isActive(IDBTransactionBackendImpl* transaction)
+{
+ bool found = false;
+ if (m_startedTransactions.contains(transaction))
+ found = true;
+ if (m_runningTransactions.contains(transaction)) {
+ ASSERT(!found);
+ found = true;
+ }
+ ASSERT(found == m_transactions.contains(transaction));
+ return found;
+}
+#endif
+
+void IDBTransactionCoordinator::processStartedTransactions()
+{
+ // FIXME: For now, we only allow one transaction to run at a time.
+ if (!m_runningTransactions.isEmpty())
+ return;
+
+ if (m_startedTransactions.isEmpty())
+ return;
+
+ IDBTransactionBackendImpl* transaction = *m_startedTransactions.begin();
+ m_startedTransactions.remove(transaction);
+ m_runningTransactions.add(transaction);
+ transaction->run();
+}
+
+};
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/IDBTransactionCoordinator.h b/Source/WebCore/storage/IDBTransactionCoordinator.h
new file mode 100644
index 0000000..ef99e73
--- /dev/null
+++ b/Source/WebCore/storage/IDBTransactionCoordinator.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:
+ *
+ * 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 IDBTransactionCoordinator_h
+#define IDBTransactionCoordinator_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "DOMStringList.h"
+#include "IDBTransactionBackendInterface.h"
+#include <wtf/ListHashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBTransactionBackendImpl;
+class IDBTransactionCallbacks;
+class IDBDatabaseBackendImpl;
+
+// Transactions are executed in the order the were created.
+class IDBTransactionCoordinator : public RefCounted<IDBTransactionCoordinator> {
+public:
+ static PassRefPtr<IDBTransactionCoordinator> create();
+ virtual ~IDBTransactionCoordinator();
+
+ // Called by transactions as they start and finish.
+ void didCreateTransaction(IDBTransactionBackendImpl*);
+ void didStartTransaction(IDBTransactionBackendImpl*);
+ void didFinishTransaction(IDBTransactionBackendImpl*);
+
+#ifndef NDEBUG
+ bool isActive(IDBTransactionBackendImpl*);
+#endif
+
+private:
+ IDBTransactionCoordinator();
+
+ void processStartedTransactions();
+
+ // This is just an efficient way to keep references to all transactions.
+ HashMap<IDBTransactionBackendImpl*, RefPtr<IDBTransactionBackendImpl> > m_transactions;
+ // Transactions in different states are grouped below.
+ ListHashSet<IDBTransactionBackendImpl*> m_startedTransactions;
+ HashSet<IDBTransactionBackendImpl*> m_runningTransactions;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBTransactionCoordinator_h
diff --git a/Source/WebCore/storage/LocalStorageTask.cpp b/Source/WebCore/storage/LocalStorageTask.cpp
new file mode 100644
index 0000000..d31c991
--- /dev/null
+++ b/Source/WebCore/storage/LocalStorageTask.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "LocalStorageTask.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "LocalStorageThread.h"
+#include "StorageAreaSync.h"
+
+namespace WebCore {
+
+LocalStorageTask::LocalStorageTask(Type type, StorageAreaSync* area)
+ : m_type(type)
+ , m_area(area)
+ , m_thread(0)
+{
+ ASSERT(m_area);
+ ASSERT(m_type == AreaImport || m_type == AreaSync || m_type == DeleteEmptyDatabase);
+}
+
+LocalStorageTask::LocalStorageTask(Type type, LocalStorageThread* thread)
+ : m_type(type)
+ , m_area(0)
+ , m_thread(thread)
+{
+ ASSERT(m_thread);
+ ASSERT(m_type == TerminateThread);
+}
+
+LocalStorageTask::~LocalStorageTask()
+{
+}
+
+void LocalStorageTask::performTask()
+{
+ switch (m_type) {
+ case AreaImport:
+ m_area->performImport();
+ break;
+ case AreaSync:
+ m_area->performSync();
+ break;
+ case DeleteEmptyDatabase:
+ m_area->deleteEmptyDatabase();
+ break;
+ case TerminateThread:
+ m_thread->performTerminate();
+ break;
+ }
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/LocalStorageTask.h b/Source/WebCore/storage/LocalStorageTask.h
new file mode 100644
index 0000000..a2e35ea
--- /dev/null
+++ b/Source/WebCore/storage/LocalStorageTask.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 LocalStorageTask_h
+#define LocalStorageTask_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+ class StorageAreaSync;
+ class LocalStorageThread;
+
+ // FIXME: Rename this class to StorageTask
+ class LocalStorageTask : public Noncopyable {
+ public:
+ enum Type { AreaImport, AreaSync, DeleteEmptyDatabase, TerminateThread };
+
+ ~LocalStorageTask();
+
+ static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(AreaImport, area)); }
+ static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(AreaSync, area)); }
+ static PassOwnPtr<LocalStorageTask> createDeleteEmptyDatabase(StorageAreaSync* area) { return adoptPtr(new LocalStorageTask(DeleteEmptyDatabase, area)); }
+ static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return adoptPtr(new LocalStorageTask(TerminateThread, thread)); }
+
+ void performTask();
+
+ private:
+ LocalStorageTask(Type, StorageAreaSync*);
+ LocalStorageTask(Type, LocalStorageThread*);
+
+ Type m_type;
+ StorageAreaSync* m_area;
+ LocalStorageThread* m_thread;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // LocalStorageTask_h
diff --git a/Source/WebCore/storage/LocalStorageThread.cpp b/Source/WebCore/storage/LocalStorageThread.cpp
new file mode 100644
index 0000000..cbb81c5
--- /dev/null
+++ b/Source/WebCore/storage/LocalStorageThread.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "LocalStorageThread.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "LocalStorageTask.h"
+#include "StorageAreaSync.h"
+
+namespace WebCore {
+
+PassOwnPtr<LocalStorageThread> LocalStorageThread::create()
+{
+ return adoptPtr(new LocalStorageThread);
+}
+
+LocalStorageThread::LocalStorageThread()
+ : m_threadID(0)
+{
+}
+
+LocalStorageThread::~LocalStorageThread()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_threadID);
+}
+
+bool LocalStorageThread::start()
+{
+ ASSERT(isMainThread());
+ if (!m_threadID)
+ m_threadID = createThread(LocalStorageThread::threadEntryPointCallback, this, "WebCore: LocalStorage");
+ return m_threadID;
+}
+
+void* LocalStorageThread::threadEntryPointCallback(void* thread)
+{
+ return static_cast<LocalStorageThread*>(thread)->threadEntryPoint();
+}
+
+void* LocalStorageThread::threadEntryPoint()
+{
+ ASSERT(!isMainThread());
+ while (OwnPtr<LocalStorageTask> task = m_queue.waitForMessage())
+ task->performTask();
+
+ return 0;
+}
+
+void LocalStorageThread::scheduleTask(PassOwnPtr<LocalStorageTask> task)
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_queue.killed() && m_threadID);
+ m_queue.append(task);
+}
+
+void LocalStorageThread::terminate()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_queue.killed() && m_threadID);
+ // Even in weird, exceptional cases, don't wait on a nonexistent thread to terminate.
+ if (!m_threadID)
+ return;
+
+ void* returnValue;
+ m_queue.append(LocalStorageTask::createTerminate(this));
+ waitForThreadCompletion(m_threadID, &returnValue);
+ ASSERT(m_queue.killed());
+ m_threadID = 0;
+}
+
+void LocalStorageThread::performTerminate()
+{
+ ASSERT(!isMainThread());
+ m_queue.kill();
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/LocalStorageThread.h b/Source/WebCore/storage/LocalStorageThread.h
new file mode 100644
index 0000000..6f05911
--- /dev/null
+++ b/Source/WebCore/storage/LocalStorageThread.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 LocalStorageThread_h
+#define LocalStorageThread_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include <wtf/HashSet.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+ class StorageAreaSync;
+ class LocalStorageTask;
+
+ // FIXME: Rename this class to StorageThread
+ class LocalStorageThread : public Noncopyable {
+ public:
+ static PassOwnPtr<LocalStorageThread> create();
+ ~LocalStorageThread();
+
+ bool start();
+ void terminate();
+ void scheduleTask(PassOwnPtr<LocalStorageTask>);
+
+ // Background thread part of the terminate procedure.
+ void performTerminate();
+
+ private:
+ LocalStorageThread();
+
+ // Called on background thread.
+ static void* threadEntryPointCallback(void*);
+ void* threadEntryPoint();
+
+ ThreadIdentifier m_threadID;
+ MessageQueue<LocalStorageTask> m_queue;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // LocalStorageThread_h
diff --git a/Source/WebCore/storage/OriginQuotaManager.cpp b/Source/WebCore/storage/OriginQuotaManager.cpp
new file mode 100644
index 0000000..0f415c1
--- /dev/null
+++ b/Source/WebCore/storage/OriginQuotaManager.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 Apple 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 "OriginQuotaManager.h"
+
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
+#include "OriginUsageRecord.h"
+
+namespace WebCore {
+
+OriginQuotaManager::OriginQuotaManager()
+#ifndef NDEBUG
+ : m_usageRecordGuardLocked(false)
+#endif
+{
+}
+
+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();
+#ifndef NDEBUG
+ m_usageRecordGuardLocked = true;
+#endif
+}
+
+void OriginQuotaManager::unlock()
+{
+#ifndef NDEBUG
+ m_usageRecordGuardLocked = false;
+#endif
+ m_usageRecordGuard.unlock();
+}
+
+void OriginQuotaManager::trackOrigin(PassRefPtr<SecurityOrigin> origin)
+{
+ ASSERT(m_usageRecordGuardLocked);
+ ASSERT(!m_usageMap.contains(origin.get()));
+
+ m_usageMap.set(origin->threadsafeCopy(), new OriginUsageRecord);
+}
+
+bool OriginQuotaManager::tracksOrigin(SecurityOrigin* origin) const
+{
+ ASSERT(m_usageRecordGuardLocked);
+ return m_usageMap.contains(origin);
+}
+
+void OriginQuotaManager::addDatabase(SecurityOrigin* origin, const String& databaseIdentifier, const String& fullPath)
+{
+ ASSERT(m_usageRecordGuardLocked);
+
+ OriginUsageRecord* usageRecord = m_usageMap.get(origin);
+ ASSERT(usageRecord);
+
+ usageRecord->addDatabase(databaseIdentifier.threadsafeCopy(), fullPath.threadsafeCopy());
+}
+
+void OriginQuotaManager::removeDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
+{
+ ASSERT(m_usageRecordGuardLocked);
+
+ if (OriginUsageRecord* usageRecord = m_usageMap.get(origin))
+ usageRecord->removeDatabase(databaseIdentifier);
+}
+
+void OriginQuotaManager::removeOrigin(SecurityOrigin* origin)
+{
+ ASSERT(m_usageRecordGuardLocked);
+
+ if (OriginUsageRecord* usageRecord = m_usageMap.get(origin)) {
+ m_usageMap.remove(origin);
+ delete usageRecord;
+ }
+}
+
+void OriginQuotaManager::markDatabase(AbstractDatabase* database)
+{
+ ASSERT(database);
+ ASSERT(m_usageRecordGuardLocked);
+ OriginUsageRecord* usageRecord = m_usageMap.get(database->securityOrigin());
+ ASSERT(usageRecord);
+
+ usageRecord->markDatabase(database->stringIdentifier());
+}
+
+unsigned long long OriginQuotaManager::diskUsage(SecurityOrigin* origin) const
+{
+ ASSERT(m_usageRecordGuardLocked);
+
+ OriginUsageRecord* usageRecord = m_usageMap.get(origin);
+ ASSERT(usageRecord);
+
+ return usageRecord->diskUsage();
+}
+
+}
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/OriginQuotaManager.h b/Source/WebCore/storage/OriginQuotaManager.h
new file mode 100644
index 0000000..ec9620c
--- /dev/null
+++ b/Source/WebCore/storage/OriginQuotaManager.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 Apple 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 OriginQuotaManager_h
+#define OriginQuotaManager_h
+
+#if ENABLE(DATABASE)
+
+#include "SecurityOriginHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/Threading.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class AbstractDatabase;
+class OriginUsageRecord;
+
+class OriginQuotaManager : public Noncopyable {
+public:
+ OriginQuotaManager();
+
+ bool tryLock();
+ void lock();
+ void unlock();
+
+ void trackOrigin(PassRefPtr<SecurityOrigin>);
+ bool tracksOrigin(SecurityOrigin*) const;
+ void addDatabase(SecurityOrigin*, const String& databaseIdentifier, const String& fullPath);
+ void removeDatabase(SecurityOrigin*, const String& databaseIdentifier);
+ void removeOrigin(SecurityOrigin*);
+
+ void markDatabase(AbstractDatabase*); // Mark dirtiness of a specific database.
+ unsigned long long diskUsage(SecurityOrigin*) const;
+
+private:
+ mutable Mutex m_usageRecordGuard;
+#ifndef NDEBUG
+ bool m_usageRecordGuardLocked;
+#endif
+
+ typedef HashMap<RefPtr<SecurityOrigin>, OriginUsageRecord*, SecurityOriginHash> OriginUsageMap;
+ OriginUsageMap m_usageMap;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // OriginQuotaManager_h
diff --git a/Source/WebCore/storage/OriginUsageRecord.cpp b/Source/WebCore/storage/OriginUsageRecord.cpp
new file mode 100644
index 0000000..eac08fd
--- /dev/null
+++ b/Source/WebCore/storage/OriginUsageRecord.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 Apple 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 "OriginUsageRecord.h"
+
+#if ENABLE(DATABASE)
+
+#include "SQLiteFileSystem.h"
+
+namespace WebCore {
+
+OriginUsageRecord::OriginUsageRecord()
+ : m_cachedDiskUsageIsValid(false)
+{
+}
+
+void OriginUsageRecord::addDatabase(const String& identifier, const String& fullPath)
+{
+ ASSERT(!m_databaseMap.contains(identifier));
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef() || identifier.isEmpty());
+ ASSERT_ARG(fullPath, fullPath.impl()->hasOneRef() || fullPath.isEmpty());
+
+ m_databaseMap.set(identifier, DatabaseEntry(fullPath));
+ m_unknownSet.add(identifier);
+
+ m_cachedDiskUsageIsValid = false;
+}
+
+void OriginUsageRecord::removeDatabase(const String& identifier)
+{
+ ASSERT(m_databaseMap.contains(identifier));
+
+ m_databaseMap.remove(identifier);
+ m_unknownSet.remove(identifier);
+ m_cachedDiskUsageIsValid = false;
+}
+
+void OriginUsageRecord::markDatabase(const String& identifier)
+{
+ ASSERT(m_databaseMap.contains(identifier));
+ ASSERT_ARG(identifier, identifier.impl()->hasOneRef() || identifier.isEmpty());
+
+ m_unknownSet.add(identifier);
+ m_cachedDiskUsageIsValid = false;
+}
+
+unsigned long long OriginUsageRecord::diskUsage()
+{
+ // Use the last cached usage value if we have it.
+ if (m_cachedDiskUsageIsValid)
+ return m_cachedDiskUsage;
+
+ // stat() for the sizes known to be dirty.
+ HashSet<String>::iterator iUnknown = m_unknownSet.begin();
+ HashSet<String>::iterator endUnknown = m_unknownSet.end();
+ for (; iUnknown != endUnknown; ++iUnknown) {
+ const String& path = m_databaseMap.get(*iUnknown).filename;
+ ASSERT(!path.isEmpty());
+
+ // When we can't determine the file size, we'll just have to assume the file is missing/inaccessible.
+ long long size = SQLiteFileSystem::getDatabaseFileSize(path);
+ m_databaseMap.set(*iUnknown, DatabaseEntry(path, size));
+ }
+ m_unknownSet.clear();
+
+ // Recalculate the cached usage value.
+ m_cachedDiskUsage = 0;
+ HashMap<String, DatabaseEntry>::iterator iDatabase = m_databaseMap.begin();
+ HashMap<String, DatabaseEntry>::iterator endDatabase = m_databaseMap.end();
+ for (; iDatabase != endDatabase; ++iDatabase)
+ m_cachedDiskUsage += iDatabase->second.size;
+
+ m_cachedDiskUsageIsValid = true;
+ return m_cachedDiskUsage;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/storage/OriginUsageRecord.h b/Source/WebCore/storage/OriginUsageRecord.h
new file mode 100644
index 0000000..a830e68
--- /dev/null
+++ b/Source/WebCore/storage/OriginUsageRecord.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Apple 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 OriginUsageRecord_h
+#define OriginUsageRecord_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+// Objects of this class can be used from multiple threads with external synchronization.
+// String arguments are also supposed to be deeply copied by the caller when necessary.
+class OriginUsageRecord : public Noncopyable {
+public:
+ OriginUsageRecord();
+
+ void addDatabase(const String& identifier, const String& fullPath);
+ void removeDatabase(const String& identifier);
+ void markDatabase(const String& identifier); // Size may have changed, and will need to be recalculated.
+ unsigned long long diskUsage();
+
+private:
+ struct DatabaseEntry {
+ DatabaseEntry() { }
+ DatabaseEntry(const String& filename) : filename(filename) { }
+ DatabaseEntry(const String& filename, unsigned long long size) : filename(filename), size(size) { }
+ String filename;
+ unsigned long long size; // This member remains uninitialized until disk usage is calculated.
+ };
+ HashMap<String, DatabaseEntry> m_databaseMap;
+ HashSet<String> m_unknownSet;
+
+ unsigned long long m_cachedDiskUsage;
+ bool m_cachedDiskUsageIsValid;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif
diff --git a/Source/WebCore/storage/SQLError.h b/Source/WebCore/storage/SQLError.h
new file mode 100644
index 0000000..496145a
--- /dev/null
+++ b/Source/WebCore/storage/SQLError.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLError_h
+#define SQLError_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLError : public ThreadSafeShared<SQLError> {
+public:
+ static PassRefPtr<SQLError> create(unsigned code, const String& message) { return adoptRef(new SQLError(code, message)); }
+
+ 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;
+ String m_message;
+};
+
+}
+
+#endif
+
+#endif // SQLError_h
diff --git a/Source/WebCore/storage/SQLError.idl b/Source/WebCore/storage/SQLError.idl
new file mode 100644
index 0000000..87be8c7
--- /dev/null
+++ b/Source/WebCore/storage/SQLError.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Apple 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,
+ 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/Source/WebCore/storage/SQLException.h b/Source/WebCore/storage/SQLException.h
new file mode 100644
index 0000000..a0f118d
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLException.idl b/Source/WebCore/storage/SQLException.idl
new file mode 100644
index 0000000..cbbc311
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLResultSet.cpp b/Source/WebCore/storage/SQLResultSet.cpp
new file mode 100644
index 0000000..7482628
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSet.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Apple 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 "SQLResultSet.h"
+
+#if ENABLE(DATABASE)
+
+namespace WebCore {
+
+static unsigned const MaxErrorCode = 2;
+
+SQLResultSet::SQLResultSet()
+ : m_rows(SQLResultSetRowList::create())
+ , m_insertId(0)
+ , m_insertIdSet(false)
+ , m_rowsAffected(0)
+{
+}
+
+int64_t SQLResultSet::insertId(ExceptionCode& e) const
+{
+ // 4.11.4 - Return the id of the last row inserted as a result of the query
+ // If the query didn't result in any rows being added, raise an INVALID_ACCESS_ERR exception
+ if (m_insertIdSet)
+ return m_insertId;
+
+ e = INVALID_ACCESS_ERR;
+ return -1;
+}
+
+int SQLResultSet::rowsAffected() const
+{
+ return m_rowsAffected;
+}
+
+SQLResultSetRowList* SQLResultSet::rows() const
+{
+ return m_rows.get();
+}
+
+void SQLResultSet::setInsertId(int64_t id)
+{
+ ASSERT(!m_insertIdSet);
+
+ m_insertId = id;
+ m_insertIdSet = true;
+}
+
+void SQLResultSet::setRowsAffected(int count)
+{
+ m_rowsAffected = count;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/storage/SQLResultSet.h b/Source/WebCore/storage/SQLResultSet.h
new file mode 100644
index 0000000..268472f
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSet.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLResultSet_h
+#define SQLResultSet_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionCode.h"
+#include "SQLResultSetRowList.h"
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLResultSet : public ThreadSafeShared<SQLResultSet> {
+public:
+ static PassRefPtr<SQLResultSet> create() { return adoptRef(new SQLResultSet); }
+
+ SQLResultSetRowList* rows() const;
+
+ int64_t insertId(ExceptionCode&) const;
+ int rowsAffected() const;
+
+// For internal (non-JS) use
+ void setInsertId(int64_t);
+ void setRowsAffected(int);
+
+private:
+ SQLResultSet();
+
+ RefPtr<SQLResultSetRowList> m_rows;
+ int64_t m_insertId;
+ bool m_insertIdSet;
+ int m_rowsAffected;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // SQLResultSet_h
diff --git a/Source/WebCore/storage/SQLResultSet.idl b/Source/WebCore/storage/SQLResultSet.idl
new file mode 100644
index 0000000..52f06da
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSet.idl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Apple 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,
+ 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/Source/WebCore/storage/SQLResultSetRowList.cpp b/Source/WebCore/storage/SQLResultSetRowList.cpp
new file mode 100644
index 0000000..c1e4844
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSetRowList.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Apple 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 "SQLResultSetRowList.h"
+
+#if ENABLE(DATABASE)
+
+namespace WebCore {
+
+unsigned SQLResultSetRowList::length() const
+{
+ if (m_result.size() == 0)
+ return 0;
+
+ ASSERT(m_result.size() % m_columns.size() == 0);
+
+ return m_result.size() / m_columns.size();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/storage/SQLResultSetRowList.h b/Source/WebCore/storage/SQLResultSetRowList.h
new file mode 100644
index 0000000..92b5ec0
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSetRowList.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLResultSetRowList_h
+#define SQLResultSetRowList_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/PassRefPtr.h>
+#include "SQLValue.h"
+
+namespace WebCore {
+
+class SQLResultSetRowList : public RefCounted<SQLResultSetRowList> {
+public:
+ static PassRefPtr<SQLResultSetRowList> create() { return adoptRef(new SQLResultSetRowList); }
+
+ const Vector<String>& columnNames() const { return m_columns; }
+ const Vector<SQLValue>& values() const { return m_result; }
+
+ void addColumn(const String& name) { m_columns.append(name); }
+ void addResult(const SQLValue& result) { m_result.append(result); }
+
+ unsigned length() const;
+
+private:
+ SQLResultSetRowList() { }
+
+ Vector<String> m_columns;
+ Vector<SQLValue> m_result;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebCore/storage/SQLResultSetRowList.idl b/Source/WebCore/storage/SQLResultSetRowList.idl
new file mode 100644
index 0000000..26239cb
--- /dev/null
+++ b/Source/WebCore/storage/SQLResultSetRowList.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Apple 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,
+ OmitConstructor,
+ NoStaticTables
+ ] SQLResultSetRowList {
+ readonly attribute unsigned long length;
+ [Custom] DOMObject item(in unsigned long index);
+ };
+}
diff --git a/Source/WebCore/storage/SQLStatement.cpp b/Source/WebCore/storage/SQLStatement.cpp
new file mode 100644
index 0000000..306f561
--- /dev/null
+++ b/Source/WebCore/storage/SQLStatement.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2007 Apple 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 "SQLStatement.h"
+
+#if ENABLE(DATABASE)
+
+#include "Database.h"
+#include "Logging.h"
+#include "SQLError.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include "SQLStatementCallback.h"
+#include "SQLStatementErrorCallback.h"
+#include "SQLTransaction.h"
+#include "SQLValue.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+PassRefPtr<SQLStatement> SQLStatement::create(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions)
+{
+ return adoptRef(new SQLStatement(statement, arguments, callback, errorCallback, permissions));
+}
+
+SQLStatement::SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, int permissions)
+ : m_statement(statement.crossThreadString())
+ , m_arguments(arguments)
+ , m_statementCallback(callback)
+ , m_statementErrorCallback(errorCallback)
+ , m_permissions(permissions)
+{
+}
+
+bool SQLStatement::execute(Database* db)
+{
+ ASSERT(!m_resultSet);
+
+ // If we're re-running this statement after a quota violation, we need to clear that error now
+ clearFailureDueToQuota();
+
+ // This transaction might have been marked bad while it was being set up on the main thread,
+ // so if there is still an error, return false.
+ if (m_error)
+ return false;
+
+ db->setAuthorizerPermissions(m_permissions);
+
+ 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(result == SQLResultInterrupt ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, database->lastErrorMsg());
+ return false;
+ }
+
+ // FIXME: If the statement uses the ?### syntax supported by sqlite, the bind parameter count is very likely off from the number of question marks.
+ // 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(db->isInterrupted() ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count");
+ return false;
+ }
+
+ for (unsigned i = 0; i < m_arguments.size(); ++i) {
+ result = statement.bindValue(i + 1, m_arguments[i]);
+ if (result == SQLResultFull) {
+ setFailureDueToQuota();
+ return false;
+ }
+
+ 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(SQLError::DATABASE_ERR, database->lastErrorMsg());
+ return false;
+ }
+ }
+
+ 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) {
+ 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->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(SQLError::DATABASE_ERR, database->lastErrorMsg());
+ return false;
+ }
+
+ // FIXME: If the spec allows triggers, and we want to be "accurate" in a different way, we'd use
+ // sqlite3_total_changes() here instead of sqlite3_changed, because that includes rows modified from within a trigger
+ // For now, this seems sufficient
+ resultSet->setRowsAffected(database->lastChanges());
+
+ m_resultSet = resultSet;
+ return true;
+}
+
+void SQLStatement::setDatabaseDeletedError()
+{
+ ASSERT(!m_error && !m_resultSet);
+ 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(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match");
+}
+
+bool SQLStatement::performCallback(SQLTransaction* transaction)
+{
+ ASSERT(transaction);
+
+ bool callbackError = false;
+
+ // Call the appropriate statement callback and track if it resulted in an error,
+ // 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());
+ } else if (m_statementCallback)
+ callbackError = !m_statementCallback->handleEvent(transaction, m_resultSet.get());
+
+ // Now release our callbacks, to break reference cycles.
+ m_statementCallback = 0;
+ m_statementErrorCallback = 0;
+
+ return callbackError;
+}
+
+void SQLStatement::setFailureDueToQuota()
+{
+ ASSERT(!m_error && !m_resultSet);
+ 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()
+{
+ if (lastExecutionFailedDueToQuota())
+ m_error = 0;
+}
+
+bool SQLStatement::lastExecutionFailedDueToQuota() const
+{
+ return m_error && m_error->code() == SQLError::QUOTA_ERR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/SQLStatement.h b/Source/WebCore/storage/SQLStatement.h
new file mode 100644
index 0000000..afd605a
--- /dev/null
+++ b/Source/WebCore/storage/SQLStatement.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLStatement_h
+#define SQLStatement_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include "SQLResultSet.h"
+#include "SQLValue.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Database;
+class SQLError;
+class SQLStatementCallback;
+class SQLStatementErrorCallback;
+class SQLTransaction;
+
+class SQLStatement : public ThreadSafeShared<SQLStatement> {
+public:
+ static PassRefPtr<SQLStatement> create(const String&, const Vector<SQLValue>&, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions);
+
+ bool execute(Database*);
+ bool lastExecutionFailedDueToQuota() const;
+
+ bool hasStatementCallback() const { return m_statementCallback; }
+ bool hasStatementErrorCallback() const { return m_statementErrorCallback; }
+
+ void setDatabaseDeletedError();
+ void setVersionMismatchedError();
+
+ bool performCallback(SQLTransaction*);
+
+ SQLError* sqlError() const { return m_error.get(); }
+private:
+ SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, int permissions);
+
+ void setFailureDueToQuota();
+ void clearFailureDueToQuota();
+
+ String m_statement;
+ Vector<SQLValue> m_arguments;
+ RefPtr<SQLStatementCallback> m_statementCallback;
+ RefPtr<SQLStatementErrorCallback> m_statementErrorCallback;
+
+ RefPtr<SQLError> m_error;
+ RefPtr<SQLResultSet> m_resultSet;
+
+ int m_permissions;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // SQLStatement_h
diff --git a/Source/WebCore/storage/SQLStatementCallback.h b/Source/WebCore/storage/SQLStatementCallback.h
new file mode 100644
index 0000000..f86e29f
--- /dev/null
+++ b/Source/WebCore/storage/SQLStatementCallback.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLStatementCallback_h
+#define SQLStatementCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLTransaction;
+class SQLResultSet;
+
+class SQLStatementCallback : public ThreadSafeShared<SQLStatementCallback> {
+public:
+ virtual ~SQLStatementCallback() { }
+ virtual bool handleEvent(SQLTransaction*, SQLResultSet*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLStatementErrorCallback_h
diff --git a/Source/WebCore/storage/SQLStatementCallback.idl b/Source/WebCore/storage/SQLStatementCallback.idl
new file mode 100644
index 0000000..cc25711
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLStatementErrorCallback.h b/Source/WebCore/storage/SQLStatementErrorCallback.h
new file mode 100644
index 0000000..acb8f64
--- /dev/null
+++ b/Source/WebCore/storage/SQLStatementErrorCallback.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLStatementErrorCallback_h
+#define SQLStatementErrorCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLTransaction;
+class SQLError;
+
+class SQLStatementErrorCallback : public ThreadSafeShared<SQLStatementErrorCallback> {
+public:
+ virtual ~SQLStatementErrorCallback() { }
+ virtual bool handleEvent(SQLTransaction*, SQLError*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLStatementErrorCallback_h
diff --git a/Source/WebCore/storage/SQLStatementErrorCallback.idl b/Source/WebCore/storage/SQLStatementErrorCallback.idl
new file mode 100644
index 0000000..315500d
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLStatementSync.cpp b/Source/WebCore/storage/SQLStatementSync.cpp
new file mode 100644
index 0000000..673d50d
--- /dev/null
+++ b/Source/WebCore/storage/SQLStatementSync.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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, int permissions)
+ : m_statement(statement)
+ , m_arguments(arguments)
+ , m_permissions(permissions)
+{
+ ASSERT(!m_statement.isEmpty());
+}
+
+PassRefPtr<SQLResultSet> SQLStatementSync::execute(DatabaseSync* db, ExceptionCode& ec)
+{
+ db->setAuthorizerPermissions(m_permissions);
+
+ SQLiteDatabase* database = &db->sqliteDatabase();
+
+ SQLiteStatement statement(*database, m_statement);
+ int result = statement.prepare();
+ if (result != SQLResultOk) {
+ ec = (result == SQLResultInterrupt ? SQLException::DATABASE_ERR : SQLException::SYNTAX_ERR);
+ return 0;
+ }
+
+ if (statement.bindParameterCount() != m_arguments.size()) {
+ ec = (db->isInterrupted()? SQLException::DATABASE_ERR : 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/Source/WebCore/storage/SQLStatementSync.h b/Source/WebCore/storage/SQLStatementSync.h
new file mode 100644
index 0000000..d807e55
--- /dev/null
+++ b/Source/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, int permissions);
+
+ PassRefPtr<SQLResultSet> execute(DatabaseSync*, ExceptionCode&);
+
+private:
+ String m_statement;
+ Vector<SQLValue> m_arguments;
+ int m_permissions;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
+
+#endif // SQLStatementSync_h
diff --git a/Source/WebCore/storage/SQLTransaction.cpp b/Source/WebCore/storage/SQLTransaction.cpp
new file mode 100644
index 0000000..dea9d97
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransaction.cpp
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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 "SQLTransaction.h"
+
+#if ENABLE(DATABASE)
+
+#include "Database.h"
+#include "DatabaseAuthorizer.h"
+#include "DatabaseThread.h"
+#include "Logging.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "SQLError.h"
+#include "SQLiteTransaction.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.
+// In the future we decide to track if a size increase wasn't enough, and ask for larger-and-larger increases until its enough.
+static const int DefaultQuotaSizeIncrease = 1048576;
+
+namespace WebCore {
+
+PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
+{
+ 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)
+ : m_nextStep(&SQLTransaction::acquireLock)
+ , m_executeSqlAllowed(false)
+ , m_database(db)
+ , m_wrapper(wrapper)
+ , m_callback(callback)
+ , m_successCallback(successCallback)
+ , m_errorCallback(errorCallback)
+ , m_shouldRetryCurrentStatement(false)
+ , m_modifiedDatabase(false)
+ , m_lockAcquired(false)
+ , m_readOnly(readOnly)
+{
+ ASSERT(m_database);
+}
+
+SQLTransaction::~SQLTransaction()
+{
+ ASSERT(!m_sqliteTransaction);
+}
+
+void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)
+{
+ if (!m_executeSqlAllowed || !m_database->opened()) {
+ e = INVALID_STATE_ERR;
+ return;
+ }
+
+ int permissions = DatabaseAuthorizer::ReadWriteMask;
+ if (!m_database->scriptExecutionContext()->allowDatabaseAccess())
+ permissions |= DatabaseAuthorizer::NoAccessMask;
+ else if (m_readOnly)
+ permissions |= DatabaseAuthorizer::ReadOnlyMask;
+
+ RefPtr<SQLStatement> statement = SQLStatement::create(sqlStatement, arguments, callback, callbackError, permissions);
+
+ if (m_database->deleted())
+ statement->setDatabaseDeletedError();
+
+ if (!m_database->versionMatchesExpected())
+ statement->setVersionMismatchedError();
+
+ enqueueStatement(statement);
+}
+
+void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement)
+{
+ MutexLocker locker(m_statementMutex);
+ m_statementQueue.append(statement);
+}
+
+#ifndef NDEBUG
+const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step)
+{
+ if (step == &SQLTransaction::acquireLock)
+ return "acquireLock";
+ else if (step == &SQLTransaction::openTransactionAndPreflight)
+ return "openTransactionAndPreflight";
+ else if (step == &SQLTransaction::runStatements)
+ return "runStatements";
+ else if (step == &SQLTransaction::postflightAndCommit)
+ return "postflightAndCommit";
+ else if (step == &SQLTransaction::cleanupAfterTransactionErrorCallback)
+ return "cleanupAfterTransactionErrorCallback";
+ else if (step == &SQLTransaction::deliverTransactionCallback)
+ return "deliverTransactionCallback";
+ else if (step == &SQLTransaction::deliverTransactionErrorCallback)
+ return "deliverTransactionErrorCallback";
+ else if (step == &SQLTransaction::deliverStatementCallback)
+ return "deliverStatementCallback";
+ else if (step == &SQLTransaction::deliverQuotaIncreaseCallback)
+ return "deliverQuotaIncreaseCallback";
+ else if (step == &SQLTransaction::deliverSuccessCallback)
+ return "deliverSuccessCallback";
+ else if (step == &SQLTransaction::cleanupAfterSuccessCallback)
+ return "cleanupAfterSuccessCallback";
+ else
+ return "UNKNOWN";
+}
+#endif
+
+void SQLTransaction::checkAndHandleClosedOrInterruptedDatabase()
+{
+ if (m_database->opened() && !m_database->isInterrupted())
+ return;
+
+ // If the database was stopped, don't do anything and cancel queued work
+ LOG(StorageAPI, "Database was stopped or interrupted - cancelling work for this transaction");
+ MutexLocker locker(m_statementMutex);
+ m_statementQueue.clear();
+ m_nextStep = 0;
+
+ // Release the unneeded callbacks, to break reference cycles.
+ m_callback = 0;
+ m_successCallback = 0;
+ m_errorCallback = 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();
+ m_sqliteTransaction.clear();
+ }
+
+ if (m_lockAcquired)
+ m_database->transactionCoordinator()->releaseLock(this);
+}
+
+
+bool SQLTransaction::performNextStep()
+{
+ LOG(StorageAPI, "Step %s\n", debugStepName(m_nextStep));
+
+ ASSERT(m_nextStep == &SQLTransaction::acquireLock ||
+ m_nextStep == &SQLTransaction::openTransactionAndPreflight ||
+ m_nextStep == &SQLTransaction::runStatements ||
+ m_nextStep == &SQLTransaction::postflightAndCommit ||
+ m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback ||
+ m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback);
+
+ checkAndHandleClosedOrInterruptedDatabase();
+
+ if (m_nextStep)
+ (this->*m_nextStep)();
+
+ // If there is no nextStep after performing the above step, the transaction is complete
+ return !m_nextStep;
+}
+
+void SQLTransaction::performPendingCallback()
+{
+ LOG(StorageAPI, "Callback %s\n", debugStepName(m_nextStep));
+
+ ASSERT(m_nextStep == &SQLTransaction::deliverTransactionCallback ||
+ m_nextStep == &SQLTransaction::deliverTransactionErrorCallback ||
+ m_nextStep == &SQLTransaction::deliverStatementCallback ||
+ m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback ||
+ m_nextStep == &SQLTransaction::deliverSuccessCallback);
+
+ checkAndHandleClosedOrInterruptedDatabase();
+
+ if (m_nextStep)
+ (this->*m_nextStep)();
+}
+
+void SQLTransaction::notifyDatabaseThreadIsShuttingDown()
+{
+ ASSERT(currentThread() == database()->scriptExecutionContext()->databaseThread()->getThreadID());
+
+ // If the transaction is in progress, we should roll it back here, since this is our last
+ // oportunity to do something related to this transaction on the DB thread.
+ // Clearing m_sqliteTransaction invokes SQLiteTransaction's destructor which does just that.
+ m_sqliteTransaction.clear();
+}
+
+void SQLTransaction::acquireLock()
+{
+ m_database->transactionCoordinator()->acquireLock(this);
+}
+
+void SQLTransaction::lockAcquired()
+{
+ m_lockAcquired = true;
+ m_nextStep = &SQLTransaction::openTransactionAndPreflight;
+ LOG(StorageAPI, "Scheduling openTransactionAndPreflight immediately for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this, true);
+}
+
+void SQLTransaction::openTransactionAndPreflight()
+{
+ 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(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->sqliteDatabase().setMaximumSize(m_database->maximumSize());
+
+ ASSERT(!m_sqliteTransaction);
+ m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly));
+
+ m_database->resetDeletes();
+ m_database->disableAuthorizer();
+ m_sqliteTransaction->begin();
+ 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->sqliteDatabase().transactionInProgress());
+ m_sqliteTransaction.clear();
+ 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)) {
+ m_sqliteTransaction.clear();
+ m_transactionError = m_wrapper->sqlError();
+ if (!m_transactionError)
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction");
+
+ handleTransactionError(false);
+ return;
+ }
+
+ // Transaction Step 4 - Invoke the transaction callback with the new SQLTransaction object
+ m_nextStep = &SQLTransaction::deliverTransactionCallback;
+ LOG(StorageAPI, "Scheduling deliverTransactionCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+}
+
+void SQLTransaction::deliverTransactionCallback()
+{
+ bool shouldDeliverErrorCallback = false;
+
+ if (m_callback) {
+ m_executeSqlAllowed = true;
+ shouldDeliverErrorCallback = !m_callback->handleEvent(this);
+ m_executeSqlAllowed = false;
+ m_callback = 0;
+ }
+
+ // Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback
+ if (shouldDeliverErrorCallback) {
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception");
+ deliverTransactionErrorCallback();
+ } else
+ scheduleToRunStatements();
+}
+
+void SQLTransaction::scheduleToRunStatements()
+{
+ m_nextStep = &SQLTransaction::runStatements;
+ LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this);
+}
+
+void SQLTransaction::runStatements()
+{
+ ASSERT(m_lockAcquired);
+
+ // If there is a series of statements queued up that are all successful and have no associated
+ // SQLStatementCallback objects, then we can burn through the queue
+ do {
+ if (m_shouldRetryCurrentStatement && !m_sqliteTransaction->wasRolledBackBySqlite()) {
+ m_shouldRetryCurrentStatement = false;
+ // FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed.
+ // See ::openTransactionAndPreflight() for discussion
+
+ // Reset the maximum size here, as it was increased to allow us to retry this statement.
+ // 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->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
+ if (m_currentStatement && m_currentStatement->lastExecutionFailedDueToQuota()) {
+ handleCurrentStatementError();
+ break;
+ }
+
+ // Otherwise, advance to the next statement
+ getNextStatement();
+ }
+ } while (runCurrentStatement());
+
+ // If runCurrentStatement() returned false, that means either there was no current statement to run,
+ // or the current statement requires a callback to complete. In the later case, it also scheduled
+ // the callback or performed any other additional work so we can return
+ if (!m_currentStatement)
+ postflightAndCommit();
+}
+
+void SQLTransaction::getNextStatement()
+{
+ m_currentStatement = 0;
+
+ MutexLocker locker(m_statementMutex);
+ if (!m_statementQueue.isEmpty()) {
+ m_currentStatement = m_statementQueue.takeFirst();
+ }
+}
+
+bool SQLTransaction::runCurrentStatement()
+{
+ if (!m_currentStatement)
+ return false;
+
+ m_database->resetAuthorizer();
+
+ if (m_currentStatement->execute(m_database.get())) {
+ 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(database());
+ }
+
+ if (m_currentStatement->hasStatementCallback()) {
+ m_nextStep = &SQLTransaction::deliverStatementCallback;
+ LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+ return false;
+ }
+ return true;
+ }
+
+ if (m_currentStatement->lastExecutionFailedDueToQuota()) {
+ m_nextStep = &SQLTransaction::deliverQuotaIncreaseCallback;
+ LOG(StorageAPI, "Scheduling deliverQuotaIncreaseCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+ return false;
+ }
+
+ handleCurrentStatementError();
+
+ return false;
+}
+
+void SQLTransaction::handleCurrentStatementError()
+{
+ // Transaction Steps 6.error - Call the statement's error callback, but if there was no error callback,
+ // or the transaction was rolled back, jump to the transaction error callback
+ if (m_currentStatement->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) {
+ m_nextStep = &SQLTransaction::deliverStatementCallback;
+ LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+ } else {
+ m_transactionError = m_currentStatement->sqlError();
+ if (!m_transactionError)
+ m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute");
+ handleTransactionError(false);
+ }
+}
+
+void SQLTransaction::deliverStatementCallback()
+{
+ ASSERT(m_currentStatement);
+
+ // Transaction Step 6.6 and 6.3(error) - If the statement callback went wrong, jump to the transaction error callback
+ // Otherwise, continue to loop through the statement queue
+ m_executeSqlAllowed = true;
+ bool result = m_currentStatement->performCallback(this);
+ m_executeSqlAllowed = false;
+
+ if (result) {
+ 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();
+}
+
+void SQLTransaction::deliverQuotaIncreaseCallback()
+{
+ ASSERT(m_currentStatement);
+ ASSERT(!m_shouldRetryCurrentStatement);
+
+ m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database());
+
+ m_nextStep = &SQLTransaction::runStatements;
+ LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this);
+}
+
+void SQLTransaction::postflightAndCommit()
+{
+ ASSERT(m_lockAcquired);
+
+ // Transaction Step 7 - Peform postflight steps, jumping to the error callback if they fail
+ if (m_wrapper && !m_wrapper->performPostflight(this)) {
+ m_transactionError = m_wrapper->sqlError();
+ if (!m_transactionError)
+ m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction");
+ handleTransactionError(false);
+ return;
+ }
+
+ // Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails
+ 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()) {
+ m_successCallback = 0;
+ m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction");
+ handleTransactionError(false);
+ return;
+ }
+
+ // 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()->didCommitWriteTransaction(database());
+
+ // Now release our unneeded callbacks, to break reference cycles.
+ m_errorCallback = 0;
+
+ // Transaction Step 10 - Deliver success callback, if there is one
+ if (m_successCallback) {
+ m_nextStep = &SQLTransaction::deliverSuccessCallback;
+ LOG(StorageAPI, "Scheduling deliverSuccessCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+ } else
+ cleanupAfterSuccessCallback();
+}
+
+void SQLTransaction::deliverSuccessCallback()
+{
+ // Transaction Step 10 - Deliver success callback
+ ASSERT(m_successCallback);
+ m_successCallback->handleEvent();
+
+ // Release the last callback to break reference cycle
+ m_successCallback = 0;
+
+ // Schedule a "post-success callback" step to return control to the database thread in case there
+ // are further transactions queued up for this Database
+ m_nextStep = &SQLTransaction::cleanupAfterSuccessCallback;
+ LOG(StorageAPI, "Scheduling cleanupAfterSuccessCallback for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this);
+}
+
+void SQLTransaction::cleanupAfterSuccessCallback()
+{
+ ASSERT(m_lockAcquired);
+
+ // Transaction Step 11 - End transaction steps
+ // There is no next step
+ LOG(StorageAPI, "Transaction %p is complete\n", this);
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+ m_sqliteTransaction.clear();
+ m_nextStep = 0;
+
+ // Release the lock on this database
+ m_database->transactionCoordinator()->releaseLock(this);
+}
+
+void SQLTransaction::handleTransactionError(bool inCallback)
+{
+ if (m_errorCallback) {
+ if (inCallback)
+ deliverTransactionErrorCallback();
+ else {
+ m_nextStep = &SQLTransaction::deliverTransactionErrorCallback;
+ LOG(StorageAPI, "Scheduling deliverTransactionErrorCallback for transaction %p\n", this);
+ m_database->scheduleTransactionCallback(this);
+ }
+ return;
+ }
+
+ // No error callback, so fast-forward to:
+ // Transaction Step 12 - Rollback the transaction.
+ if (inCallback) {
+ m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
+ LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this);
+ } else {
+ cleanupAfterTransactionErrorCallback();
+ }
+}
+
+void SQLTransaction::deliverTransactionErrorCallback()
+{
+ ASSERT(m_transactionError);
+
+ // 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 = 0;
+ }
+
+ m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
+ LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this);
+}
+
+void SQLTransaction::cleanupAfterTransactionErrorCallback()
+{
+ ASSERT(m_lockAcquired);
+
+ m_database->disableAuthorizer();
+ if (m_sqliteTransaction) {
+ // Transaction Step 12 - Rollback the transaction.
+ m_sqliteTransaction->rollback();
+
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+ m_sqliteTransaction.clear();
+ }
+ m_database->enableAuthorizer();
+
+ // Transaction Step 12 - Any still-pending statements in the transaction are discarded.
+ {
+ MutexLocker locker(m_statementMutex);
+ m_statementQueue.clear();
+ }
+
+ // Transaction is complete! There is no next step
+ LOG(StorageAPI, "Transaction %p is complete with an error\n", this);
+ ASSERT(!m_database->sqliteDatabase().transactionInProgress());
+ m_nextStep = 0;
+
+ // Now release the lock on this database
+ m_database->transactionCoordinator()->releaseLock(this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/SQLTransaction.h b/Source/WebCore/storage/SQLTransaction.h
new file mode 100644
index 0000000..3eb1fd5
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransaction.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLTransaction_h
+#define SQLTransaction_h
+
+#if ENABLE(DATABASE)
+
+#include "ExceptionCode.h"
+#include "SQLStatement.h"
+#include <wtf/Deque.h>
+#include <wtf/Forward.h>
+#include <wtf/ThreadSafeShared.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Database;
+class SQLError;
+class SQLiteTransaction;
+class SQLStatementCallback;
+class SQLStatementErrorCallback;
+class SQLTransaction;
+class SQLTransactionCallback;
+class SQLTransactionErrorCallback;
+class SQLValue;
+class VoidCallback;
+
+class SQLTransactionWrapper : public ThreadSafeShared<SQLTransactionWrapper> {
+public:
+ virtual ~SQLTransactionWrapper() { }
+ virtual bool performPreflight(SQLTransaction*) = 0;
+ virtual bool performPostflight(SQLTransaction*) = 0;
+
+ virtual SQLError* sqlError() const = 0;
+};
+
+class SQLTransaction : public ThreadSafeShared<SQLTransaction> {
+public:
+ static PassRefPtr<SQLTransaction> create(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
+ PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>, bool readOnly = false);
+
+ ~SQLTransaction();
+
+ void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments,
+ PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, ExceptionCode&);
+
+ void lockAcquired();
+ bool performNextStep();
+ void performPendingCallback();
+
+ Database* database() { return m_database.get(); }
+ bool isReadOnly() { return m_readOnly; }
+ void notifyDatabaseThreadIsShuttingDown();
+
+private:
+ SQLTransaction(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
+ PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>, bool readOnly);
+
+ typedef void (SQLTransaction::*TransactionStepMethod)();
+ TransactionStepMethod m_nextStep;
+
+ void enqueueStatement(PassRefPtr<SQLStatement>);
+
+ void checkAndHandleClosedOrInterruptedDatabase();
+
+ void acquireLock();
+ void openTransactionAndPreflight();
+ void deliverTransactionCallback();
+ void scheduleToRunStatements();
+ void runStatements();
+ void getNextStatement();
+ bool runCurrentStatement();
+ void handleCurrentStatementError();
+ void deliverStatementCallback();
+ void deliverQuotaIncreaseCallback();
+ void postflightAndCommit();
+ void deliverSuccessCallback();
+ void cleanupAfterSuccessCallback();
+ void handleTransactionError(bool inCallback);
+ void deliverTransactionErrorCallback();
+ void cleanupAfterTransactionErrorCallback();
+
+#ifndef NDEBUG
+ static const char* debugStepName(TransactionStepMethod);
+#endif
+
+ RefPtr<SQLStatement> m_currentStatement;
+
+ bool m_executeSqlAllowed;
+
+ RefPtr<Database> m_database;
+ RefPtr<SQLTransactionWrapper> m_wrapper;
+ RefPtr<SQLTransactionCallback> m_callback;
+ RefPtr<VoidCallback> m_successCallback;
+ RefPtr<SQLTransactionErrorCallback> m_errorCallback;
+ RefPtr<SQLError> m_transactionError;
+ bool m_shouldRetryCurrentStatement;
+ bool m_modifiedDatabase;
+ bool m_lockAcquired;
+ bool m_readOnly;
+
+ Mutex m_statementMutex;
+ Deque<RefPtr<SQLStatement> > m_statementQueue;
+
+ OwnPtr<SQLiteTransaction> m_sqliteTransaction;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // SQLTransaction_h
diff --git a/Source/WebCore/storage/SQLTransaction.idl b/Source/WebCore/storage/SQLTransaction.idl
new file mode 100644
index 0000000..4e353d3
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransaction.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 Apple 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,
+ OmitConstructor,
+ NoStaticTables
+ ] SQLTransaction {
+ [Custom] void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback, in SQLStatementErrorCallback errorCallback);
+ };
+}
diff --git a/Source/WebCore/storage/SQLTransactionCallback.h b/Source/WebCore/storage/SQLTransactionCallback.h
new file mode 100644
index 0000000..aff6233
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionCallback.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *Transaction
+ * 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 SQLTransactionCallback_h
+#define SQLTransactionCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLTransaction;
+
+class SQLTransactionCallback : public ThreadSafeShared<SQLTransactionCallback> {
+public:
+ virtual ~SQLTransactionCallback() { }
+ virtual bool handleEvent(SQLTransaction*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLTransactionCallback_h
diff --git a/Source/WebCore/storage/SQLTransactionCallback.idl b/Source/WebCore/storage/SQLTransactionCallback.idl
new file mode 100644
index 0000000..d1bc77c
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLTransactionClient.cpp b/Source/WebCore/storage/SQLTransactionClient.cpp
new file mode 100644
index 0000000..6b95606
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionClient.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 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 "SQLTransactionClient.h"
+
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
+#include "DatabaseTracker.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database)
+{
+ DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
+ database->securityOrigin(), database->stringIdentifier());
+}
+
+void SQLTransactionClient::didExecuteStatement(AbstractDatabase* database)
+{
+ DatabaseTracker::tracker().databaseChanged(database);
+}
+
+bool SQLTransactionClient::didExceedQuota(AbstractDatabase* 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());
+ return (newQuota > currentQuota);
+}
+
+}
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/SQLTransactionClient.h b/Source/WebCore/storage/SQLTransactionClient.h
new file mode 100644
index 0000000..fed0657
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionClient.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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 SQLTransactionClient_h
+#define SQLTransactionClient_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+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)
+
+#endif // SQLTransactionClient_h
diff --git a/Source/WebCore/storage/SQLTransactionCoordinator.cpp b/Source/WebCore/storage/SQLTransactionCoordinator.cpp
new file mode 100644
index 0000000..104ea10
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionCoordinator.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 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 "SQLTransactionCoordinator.h"
+
+#if ENABLE(DATABASE)
+
+#include "Database.h"
+#include "SQLTransaction.h"
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static String getDatabaseIdentifier(SQLTransaction* transaction)
+{
+ Database* database = transaction->database();
+ ASSERT(database);
+ return database->stringIdentifier();
+}
+
+void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& info)
+{
+ if (info.activeWriteTransaction || info.pendingTransactions.isEmpty())
+ return;
+
+ RefPtr<SQLTransaction> firstPendingTransaction = info.pendingTransactions.first();
+ if (firstPendingTransaction->isReadOnly()) {
+ do {
+ firstPendingTransaction = info.pendingTransactions.takeFirst();
+ info.activeReadTransactions.add(firstPendingTransaction);
+ firstPendingTransaction->lockAcquired();
+ } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly());
+ } else if (info.activeReadTransactions.isEmpty()) {
+ info.pendingTransactions.removeFirst();
+ info.activeWriteTransaction = firstPendingTransaction;
+ firstPendingTransaction->lockAcquired();
+ }
+}
+
+void SQLTransactionCoordinator::acquireLock(SQLTransaction* transaction)
+{
+ String dbIdentifier = getDatabaseIdentifier(transaction);
+
+ CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
+ if (coordinationInfoIterator == m_coordinationInfoMap.end()) {
+ // No pending transactions for this DB
+ coordinationInfoIterator = m_coordinationInfoMap.add(dbIdentifier, CoordinationInfo()).first;
+ }
+
+ CoordinationInfo& info = coordinationInfoIterator->second;
+ info.pendingTransactions.append(transaction);
+ processPendingTransactions(info);
+}
+
+void SQLTransactionCoordinator::releaseLock(SQLTransaction* transaction)
+{
+ if (m_coordinationInfoMap.isEmpty())
+ return;
+
+ String dbIdentifier = getDatabaseIdentifier(transaction);
+
+ CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
+ ASSERT(coordinationInfoIterator != m_coordinationInfoMap.end());
+ CoordinationInfo& info = coordinationInfoIterator->second;
+
+ if (transaction->isReadOnly()) {
+ ASSERT(info.activeReadTransactions.contains(transaction));
+ info.activeReadTransactions.remove(transaction);
+ } else {
+ ASSERT(info.activeWriteTransaction == transaction);
+ info.activeWriteTransaction = 0;
+ }
+
+ processPendingTransactions(info);
+}
+
+void SQLTransactionCoordinator::shutdown()
+{
+ // Notify all transactions in progress that the database thread is shutting down
+ for (CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.begin();
+ coordinationInfoIterator != m_coordinationInfoMap.end(); ++coordinationInfoIterator) {
+ CoordinationInfo& info = coordinationInfoIterator->second;
+ if (info.activeWriteTransaction)
+ info.activeWriteTransaction->notifyDatabaseThreadIsShuttingDown();
+ for (HashSet<RefPtr<SQLTransaction> >::iterator activeReadTransactionsIterator =
+ info.activeReadTransactions.begin();
+ activeReadTransactionsIterator != info.activeReadTransactions.end();
+ ++activeReadTransactionsIterator) {
+ (*activeReadTransactionsIterator)->notifyDatabaseThreadIsShuttingDown();
+ }
+ }
+
+ // Clean up all pending transactions for all databases
+ m_coordinationInfoMap.clear();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/SQLTransactionCoordinator.h b/Source/WebCore/storage/SQLTransactionCoordinator.h
new file mode 100644
index 0000000..94360c0
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionCoordinator.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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 SQLTransactionCoordinator_h
+#define SQLTransactionCoordinator_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+ class SQLTransaction;
+
+ class SQLTransactionCoordinator : public Noncopyable {
+ public:
+ void acquireLock(SQLTransaction*);
+ void releaseLock(SQLTransaction*);
+ void shutdown();
+ private:
+ typedef Deque<RefPtr<SQLTransaction> > TransactionsQueue;
+ struct CoordinationInfo {
+ TransactionsQueue pendingTransactions;
+ HashSet<RefPtr<SQLTransaction> > activeReadTransactions;
+ RefPtr<SQLTransaction> activeWriteTransaction;
+ };
+ // Maps database names to information about pending transactions
+ typedef HashMap<String, CoordinationInfo> CoordinationInfoMap;
+ CoordinationInfoMap m_coordinationInfoMap;
+
+ void processPendingTransactions(CoordinationInfo& info);
+ };
+}
+
+#endif // ENABLE(DATABASE)
+
+#endif // SQLTransactionCoordinator_h
diff --git a/Source/WebCore/storage/SQLTransactionErrorCallback.h b/Source/WebCore/storage/SQLTransactionErrorCallback.h
new file mode 100644
index 0000000..4095d6a
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionErrorCallback.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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 SQLTransactionErrorCallback_h
+#define SQLTransactionErrorCallback_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class SQLError;
+
+class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> {
+public:
+ virtual ~SQLTransactionErrorCallback() { }
+ virtual bool handleEvent(SQLError*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLTransactionErrorCallback_h
diff --git a/Source/WebCore/storage/SQLTransactionErrorCallback.idl b/Source/WebCore/storage/SQLTransactionErrorCallback.idl
new file mode 100644
index 0000000..779ba69
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLTransactionSync.cpp b/Source/WebCore/storage/SQLTransactionSync.cpp
new file mode 100644
index 0000000..97a5cc5
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionSync.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 "DatabaseAuthorizer.h"
+#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(adoptPtr(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;
+
+ int permissions = DatabaseAuthorizer::ReadWriteMask;
+ if (!m_database->scriptExecutionContext()->allowDatabaseAccess())
+ permissions |= DatabaseAuthorizer::NoAccessMask;
+ else if (m_readOnly)
+ permissions |= DatabaseAuthorizer::ReadOnlyMask;
+
+ SQLStatementSync statement(sqlStatement, arguments, permissions);
+
+ 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 = adoptPtr(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(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/Source/WebCore/storage/SQLTransactionSync.h b/Source/WebCore/storage/SQLTransactionSync.h
new file mode 100644
index 0000000..e66c876
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionSync.h
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+// 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/Source/WebCore/storage/SQLTransactionSync.idl b/Source/WebCore/storage/SQLTransactionSync.idl
new file mode 100644
index 0000000..003a21d
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/SQLTransactionSyncCallback.h b/Source/WebCore/storage/SQLTransactionSyncCallback.h
new file mode 100644
index 0000000..f22e62f
--- /dev/null
+++ b/Source/WebCore/storage/SQLTransactionSyncCallback.h
@@ -0,0 +1,53 @@
+/*
+ * 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 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(SQLTransactionSync*) = 0;
+};
+
+}
+
+#endif
+
+#endif // SQLTransactionSyncCallback_h
diff --git a/Source/WebCore/storage/SQLTransactionSyncCallback.idl b/Source/WebCore/storage/SQLTransactionSyncCallback.idl
new file mode 100644
index 0000000..b0fffca
--- /dev/null
+++ b/Source/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/Source/WebCore/storage/Storage.cpp b/Source/WebCore/storage/Storage.cpp
new file mode 100644
index 0000000..0259ca4
--- /dev/null
+++ b/Source/WebCore/storage/Storage.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "Storage.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "Frame.h"
+#include "Page.h"
+#include "Settings.h"
+#include "StorageArea.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<Storage> Storage::create(Frame* frame, PassRefPtr<StorageArea> storageArea)
+{
+ return adoptRef(new Storage(frame, storageArea));
+}
+
+Storage::Storage(Frame* frame, PassRefPtr<StorageArea> storageArea)
+ : m_frame(frame)
+ , m_storageArea(storageArea)
+{
+ ASSERT(m_frame);
+ ASSERT(m_storageArea);
+}
+
+Storage::~Storage()
+{
+}
+
+unsigned Storage::length() const
+{
+ if (!m_frame || !m_frame->page() || m_frame->page()->settings()->privateBrowsingEnabled())
+ return 0;
+
+ return m_storageArea->length();
+}
+
+String Storage::key(unsigned index) const
+{
+ if (!m_frame || !m_frame->page() || m_frame->page()->settings()->privateBrowsingEnabled())
+ return String();
+
+ return m_storageArea->key(index);
+}
+
+String Storage::getItem(const String& key) const
+{
+ if (!m_frame || !m_frame->page() || m_frame->page()->settings()->privateBrowsingEnabled())
+ return String();
+
+ return m_storageArea->getItem(key);
+}
+
+void Storage::setItem(const String& key, const String& value, ExceptionCode& ec)
+{
+ ec = 0;
+ if (!m_frame)
+ return;
+
+ m_storageArea->setItem(key, value, ec, m_frame);
+}
+
+void Storage::removeItem(const String& key)
+{
+ if (!m_frame)
+ return;
+
+ m_storageArea->removeItem(key, m_frame);
+}
+
+void Storage::clear()
+{
+ if (!m_frame)
+ return;
+
+ m_storageArea->clear(m_frame);
+}
+
+bool Storage::contains(const String& key) const
+{
+ if (!m_frame || !m_frame->page() || m_frame->page()->settings()->privateBrowsingEnabled())
+ return false;
+
+ return m_storageArea->contains(key);
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/Storage.h b/Source/WebCore/storage/Storage.h
new file mode 100644
index 0000000..c81481a
--- /dev/null
+++ b/Source/WebCore/storage/Storage.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 Storage_h
+#define Storage_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class Frame;
+ class StorageArea;
+ typedef int ExceptionCode;
+
+ class Storage : public RefCounted<Storage> {
+ public:
+ static PassRefPtr<Storage> create(Frame*, PassRefPtr<StorageArea>);
+ ~Storage();
+
+ unsigned length() const;
+ String key(unsigned index) const;
+ String getItem(const String&) const;
+ void setItem(const String& key, const String& value, ExceptionCode&);
+ void removeItem(const String&);
+ void clear();
+
+ bool contains(const String& key) const;
+
+ Frame* frame() { return m_frame; }
+ void disconnectFrame() { m_frame = 0; }
+
+ private:
+ Storage(Frame*, PassRefPtr<StorageArea>);
+
+ Frame* m_frame;
+ RefPtr<StorageArea> m_storageArea;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // Storage_h
diff --git a/Source/WebCore/storage/Storage.idl b/Source/WebCore/storage/Storage.idl
new file mode 100644
index 0000000..ffd1af1
--- /dev/null
+++ b/Source/WebCore/storage/Storage.idl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 [
+ HasNameGetter,
+ CustomDeleteProperty,
+ CustomGetPropertyNames,
+ DelegatingPutFunction,
+ Conditional=DOM_STORAGE
+ ] Storage {
+ readonly attribute [DontEnum] unsigned long length;
+ [DontEnum, ConvertNullStringTo=Null] DOMString key(in unsigned long index);
+ [DontEnum, ConvertNullStringTo=Null] DOMString getItem(in DOMString key);
+ [DontEnum] void setItem(in DOMString key, in DOMString data)
+ raises(DOMException);
+ [DontEnum] void removeItem(in DOMString key);
+ [DontEnum] void clear();
+ };
+
+}
diff --git a/Source/WebCore/storage/StorageArea.h b/Source/WebCore/storage/StorageArea.h
new file mode 100644
index 0000000..6081240
--- /dev/null
+++ b/Source/WebCore/storage/StorageArea.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageArea_h
+#define StorageArea_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+ class SecurityOrigin;
+ class StorageSyncManager;
+ typedef int ExceptionCode;
+ enum StorageType { LocalStorage, SessionStorage };
+
+ // This interface is required for Chromium since these actions need to be proxied between processes.
+ class StorageArea : public RefCounted<StorageArea> {
+ public:
+ virtual ~StorageArea() { }
+
+ // The HTML5 DOM Storage API
+ virtual unsigned length() const = 0;
+ virtual String key(unsigned index) const = 0;
+ virtual String getItem(const String& key) const = 0;
+ virtual String setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame) = 0;
+ virtual String removeItem(const String& key, Frame* sourceFrame) = 0;
+ virtual bool clear(Frame* sourceFrame) = 0;
+ virtual bool contains(const String& key) const = 0;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageArea_h
diff --git a/Source/WebCore/storage/StorageAreaImpl.cpp b/Source/WebCore/storage/StorageAreaImpl.cpp
new file mode 100644
index 0000000..54df135
--- /dev/null
+++ b/Source/WebCore/storage/StorageAreaImpl.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageAreaImpl.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "Page.h"
+#include "Settings.h"
+#include "StorageAreaSync.h"
+#include "StorageEventDispatcher.h"
+#include "StorageMap.h"
+#include "StorageSyncManager.h"
+
+namespace WebCore {
+
+StorageAreaImpl::~StorageAreaImpl()
+{
+ ASSERT(isMainThread());
+}
+
+inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
+ : m_storageType(storageType)
+ , m_securityOrigin(origin)
+ , m_storageMap(StorageMap::create(quota))
+ , m_storageSyncManager(syncManager)
+#ifndef NDEBUG
+ , m_isShutdown(false)
+#endif
+{
+ 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 (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()
+{
+ ASSERT(!m_isShutdown);
+ return adoptRef(new StorageAreaImpl(this));
+}
+
+StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area)
+ : m_storageType(area->m_storageType)
+ , m_securityOrigin(area->m_securityOrigin)
+ , m_storageMap(area->m_storageMap)
+ , m_storageSyncManager(area->m_storageSyncManager)
+#ifndef NDEBUG
+ , m_isShutdown(area->m_isShutdown)
+#endif
+{
+ ASSERT(isMainThread());
+ ASSERT(m_securityOrigin);
+ ASSERT(m_storageMap);
+ ASSERT(!m_isShutdown);
+}
+
+static bool privateBrowsingEnabled(Frame* frame)
+{
+#if PLATFORM(ANDROID)
+ if (!frame)
+ return false;
+#endif
+#if PLATFORM(CHROMIUM)
+ // The frame pointer can be NULL in Chromium since this call is made in a different
+ // process from where the Frame object exists. Luckily, private browseing is
+ // implemented differently in Chromium, so it'd never return true anyway.
+ ASSERT(!frame);
+ return false;
+#else
+ return frame->page()->settings()->privateBrowsingEnabled();
+#endif
+}
+
+unsigned StorageAreaImpl::length() const
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ return m_storageMap->length();
+}
+
+String StorageAreaImpl::key(unsigned index) const
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ return m_storageMap->key(index);
+}
+
+String StorageAreaImpl::getItem(const String& key) const
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ return m_storageMap->getItem(key);
+}
+
+String StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
+{
+ ASSERT(!m_isShutdown);
+ ASSERT(!value.isNull());
+ blockUntilImportComplete();
+
+ if (privateBrowsingEnabled(frame)) {
+ ec = QUOTA_EXCEEDED_ERR;
+ return String();
+ }
+
+ String oldValue;
+ bool quotaException;
+ RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
+ if (newMap)
+ m_storageMap = newMap.release();
+
+ if (quotaException) {
+ ec = QUOTA_EXCEEDED_ERR;
+ return oldValue;
+ }
+
+ if (oldValue == value)
+ return oldValue;
+
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleItemForSync(key, value);
+ StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame);
+ return oldValue;
+}
+
+String StorageAreaImpl::removeItem(const String& key, Frame* frame)
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ if (privateBrowsingEnabled(frame))
+ return String();
+
+ String oldValue;
+ RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue);
+ if (newMap)
+ m_storageMap = newMap.release();
+
+ if (oldValue.isNull())
+ return oldValue;
+
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleItemForSync(key, String());
+ StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame);
+ return oldValue;
+}
+
+bool StorageAreaImpl::clear(Frame* frame)
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ if (privateBrowsingEnabled(frame))
+ return false;
+
+ if (!m_storageMap->length())
+ return false;
+
+ unsigned quota = m_storageMap->quota();
+ m_storageMap = StorageMap::create(quota);
+
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleClear();
+ StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame);
+ return true;
+}
+
+bool StorageAreaImpl::contains(const String& key) const
+{
+ ASSERT(!m_isShutdown);
+ blockUntilImportComplete();
+
+ return m_storageMap->contains(key);
+}
+
+void StorageAreaImpl::importItem(const String& key, const String& value)
+{
+ ASSERT(!m_isShutdown);
+ m_storageMap->importItem(key, value);
+}
+
+void StorageAreaImpl::close()
+{
+ if (m_storageAreaSync)
+ m_storageAreaSync->scheduleFinalSync();
+
+#ifndef NDEBUG
+ m_isShutdown = true;
+#endif
+}
+
+void StorageAreaImpl::blockUntilImportComplete() const
+{
+ if (m_storageAreaSync)
+ m_storageAreaSync->blockUntilImportComplete();
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageAreaImpl.h b/Source/WebCore/storage/StorageAreaImpl.h
new file mode 100644
index 0000000..60d72cb
--- /dev/null
+++ b/Source/WebCore/storage/StorageAreaImpl.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageAreaImpl_h
+#define StorageAreaImpl_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "StorageArea.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class SecurityOrigin;
+ class StorageMap;
+ class StorageAreaSync;
+
+ class StorageAreaImpl : public StorageArea {
+ public:
+ static PassRefPtr<StorageAreaImpl> create(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
+ virtual ~StorageAreaImpl();
+
+ // The HTML5 DOM Storage API (and contains)
+ virtual unsigned length() const;
+ virtual String key(unsigned index) const;
+ virtual String getItem(const String& key) const;
+ virtual String setItem(const String& key, const String& value, ExceptionCode& ec, Frame* sourceFrame);
+ virtual String removeItem(const String& key, Frame* sourceFrame);
+ virtual bool clear(Frame* sourceFrame);
+ virtual bool contains(const String& key) const;
+
+ PassRefPtr<StorageAreaImpl> copy();
+ void close();
+
+ // Only called from a background thread.
+ void importItem(const String& key, const String& value);
+
+ private:
+ StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
+ StorageAreaImpl(StorageAreaImpl*);
+
+ void blockUntilImportComplete() const;
+
+ StorageType m_storageType;
+ RefPtr<SecurityOrigin> m_securityOrigin;
+ RefPtr<StorageMap> m_storageMap;
+
+ RefPtr<StorageAreaSync> m_storageAreaSync;
+ RefPtr<StorageSyncManager> m_storageSyncManager;
+
+#ifndef NDEBUG
+ bool m_isShutdown;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageAreaImpl_h
diff --git a/Source/WebCore/storage/StorageAreaSync.cpp b/Source/WebCore/storage/StorageAreaSync.cpp
new file mode 100644
index 0000000..f2008ab
--- /dev/null
+++ b/Source/WebCore/storage/StorageAreaSync.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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
+ * 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 INC. ``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 INC. 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 "StorageAreaSync.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "EventNames.h"
+#include "FileSystem.h"
+#include "HTMLElement.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 {
+
+// If the StorageArea undergoes rapid changes, don't sync each change to disk.
+// Instead, queue up a batch of items to sync and actually do the sync at the following interval.
+static const double StorageSyncInterval = 1.0;
+
+// 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;
+
+inline StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier)
+ : m_syncTimer(this, &StorageAreaSync::syncTimerFired)
+ , m_itemsCleared(false)
+ , m_finalSyncScheduled(false)
+ , m_storageArea(storageArea)
+ , m_syncManager(storageSyncManager)
+ , 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 (!area->m_syncManager->scheduleImport(area.get()))
+ area->m_importComplete = true;
+
+ return area.release();
+}
+
+StorageAreaSync::~StorageAreaSync()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_syncTimer.isActive());
+ ASSERT(m_finalSyncScheduled);
+}
+
+void StorageAreaSync::scheduleFinalSync()
+{
+ ASSERT(isMainThread());
+ // FIXME: We do this to avoid races, but it'd be better to make things safe without blocking.
+ blockUntilImportComplete();
+ m_storageArea = 0; // This is done in blockUntilImportComplete() but this is here as a form of documentation that we must be absolutely sure the ref count cycle is broken.
+
+ if (m_syncTimer.isActive())
+ m_syncTimer.stop();
+ else {
+ // The following is balanced by the call to enableSuddenTermination in the
+ // syncTimerFired function.
+ disableSuddenTermination();
+ }
+ // FIXME: This is synchronous. We should do it on the background process, but
+ // we should do it safely.
+ m_finalSyncScheduled = true;
+ syncTimerFired(&m_syncTimer);
+ m_syncManager->scheduleDeleteEmptyDatabase(this);
+}
+
+void StorageAreaSync::scheduleItemForSync(const String& key, const String& value)
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_finalSyncScheduled);
+
+ m_changedItems.set(key, value);
+ if (!m_syncTimer.isActive()) {
+ m_syncTimer.startOneShot(StorageSyncInterval);
+
+ // The following is balanced by the call to enableSuddenTermination in the
+ // syncTimerFired function.
+ disableSuddenTermination();
+ }
+}
+
+void StorageAreaSync::scheduleClear()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_finalSyncScheduled);
+
+ m_changedItems.clear();
+ m_itemsCleared = true;
+ if (!m_syncTimer.isActive()) {
+ m_syncTimer.startOneShot(StorageSyncInterval);
+
+ // The following is balanced by the call to enableSuddenTermination in the
+ // syncTimerFired function.
+ disableSuddenTermination();
+ }
+}
+
+void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
+{
+ ASSERT(isMainThread());
+
+ 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;
+ }
+
+ 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;
+
+ // The following is balanced by the call to enableSuddenTermination in the
+ // performSync function.
+ disableSuddenTermination();
+
+ m_syncManager->scheduleSync(this);
+ }
+ }
+
+ 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();
+ }
+}
+
+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;
+ }
+
+ SQLiteStatement query(m_database, "SELECT key, value FROM ItemTable");
+ if (query.prepare() != SQLResultOk) {
+ LOG_ERROR("Unable to select items from ItemTable for local storage");
+ markImported();
+ return;
+ }
+
+ HashMap<String, String> itemMap;
+
+ int result = query.step();
+ while (result == SQLResultRow) {
+ itemMap.set(query.getColumnText(0), query.getColumnText(1));
+ result = query.step();
+ }
+
+ if (result != SQLResultDone) {
+ LOG_ERROR("Error reading items from ItemTable for local storage");
+ markImported();
+ return;
+ }
+
+ HashMap<String, String>::iterator it = itemMap.begin();
+ HashMap<String, String>::iterator end = itemMap.end();
+
+ for (; it != end; ++it)
+ m_storageArea->importItem(it->first, it->second);
+
+ markImported();
+}
+
+void StorageAreaSync::markImported()
+{
+ MutexLocker locker(m_importLock);
+ m_importComplete = true;
+ m_importCondition.signal();
+}
+
+// FIXME: In the future, we should allow use of StorageAreas while it's importing (when safe to do so).
+// Blocking everything until the import is complete is by far the simplest and safest thing to do, but
+// there is certainly room for safe optimization: Key/length will never be able to make use of such an
+// optimization (since the order of iteration can change as items are being added). Get can return any
+// item currently in the map. Get/remove can work whether or not it's in the map, but we'll need a list
+// of items the import should not overwrite. Clear can also work, but it'll need to kill the import
+// job first.
+void StorageAreaSync::blockUntilImportComplete()
+{
+ ASSERT(isMainThread());
+
+ // Fast path. We set m_storageArea to 0 only after m_importComplete being true.
+ if (!m_storageArea)
+ return;
+
+ MutexLocker locker(m_importLock);
+ while (!m_importComplete)
+ m_importCondition.wait(m_importLock);
+ m_storageArea = 0;
+}
+
+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;
+
+ // If the clear flag is set, then we clear all items out before we write any new ones in.
+ if (clearItems) {
+ SQLiteStatement clear(m_database, "DELETE FROM ItemTable");
+ if (clear.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database");
+ return;
+ }
+
+ int result = clear.step();
+ if (result != SQLResultDone) {
+ LOG_ERROR("Failed to clear all items in the local storage database - %i", result);
+ return;
+ }
+ }
+
+ SQLiteStatement insert(m_database, "INSERT INTO ItemTable VALUES (?, ?)");
+ if (insert.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database");
+ return;
+ }
+
+ SQLiteStatement remove(m_database, "DELETE FROM ItemTable WHERE key=?");
+ if (remove.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database");
+ return;
+ }
+
+ HashMap<String, String>::const_iterator end = items.end();
+
+ for (HashMap<String, String>::const_iterator it = items.begin(); it != end; ++it) {
+ // Based on the null-ness of the second argument, decide whether this is an insert or a delete.
+ SQLiteStatement& query = it->second.isNull() ? remove : insert;
+
+ query.bindText(1, it->first);
+
+ // If the second argument is non-null, we're doing an insert, so bind it as the value.
+ if (!it->second.isNull())
+ query.bindText(2, it->second);
+
+ int result = query.step();
+ if (result != SQLResultDone) {
+ LOG_ERROR("Failed to update item in the local storage database - %i", result);
+ break;
+ }
+
+ query.reset();
+ }
+}
+
+void StorageAreaSync::performSync()
+{
+ ASSERT(!isMainThread());
+
+ bool clearItems;
+ HashMap<String, String> items;
+ {
+ MutexLocker locker(m_syncLock);
+
+ ASSERT(m_syncScheduled);
+
+ clearItems = m_clearItemsWhileSyncing;
+ m_itemsPendingSync.swap(items);
+
+ 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/Source/WebCore/storage/StorageAreaSync.h b/Source/WebCore/storage/StorageAreaSync.h
new file mode 100644
index 0000000..90aa6a7
--- /dev/null
+++ b/Source/WebCore/storage/StorageAreaSync.h
@@ -0,0 +1,106 @@
+/*
+ * 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
+ * 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 INC. ``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 INC. 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 StorageAreaSync_h
+#define StorageAreaSync_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "SQLiteDatabase.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+ class Frame;
+ class StorageAreaImpl;
+ class StorageSyncManager;
+
+ class StorageAreaSync : public RefCounted<StorageAreaSync> {
+ public:
+ static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier);
+ ~StorageAreaSync();
+
+ void scheduleFinalSync();
+ void blockUntilImportComplete();
+
+ void scheduleItemForSync(const String& key, const String& value);
+ void scheduleClear();
+
+ private:
+ StorageAreaSync(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier);
+
+ void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame);
+
+ Timer<StorageAreaSync> m_syncTimer;
+ HashMap<String, String> m_changedItems;
+ bool m_itemsCleared;
+
+ bool m_finalSyncScheduled;
+
+ RefPtr<StorageAreaImpl> m_storageArea;
+ RefPtr<StorageSyncManager> m_syncManager;
+
+ // The database handle will only ever be opened and used on the background thread.
+ SQLiteDatabase m_database;
+
+ // The following members are subject to thread synchronization issues.
+ public:
+ // 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;
+
+ Mutex m_syncLock;
+ 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;
+ mutable bool m_importComplete;
+ void markImported();
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageAreaSync_h
diff --git a/Source/WebCore/storage/StorageEvent.cpp b/Source/WebCore/storage/StorageEvent.cpp
new file mode 100644
index 0000000..a08cde2
--- /dev/null
+++ b/Source/WebCore/storage/StorageEvent.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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 INC. ``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 INC. 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 "StorageEvent.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "Storage.h"
+
+namespace WebCore {
+
+PassRefPtr<StorageEvent> StorageEvent::create()
+{
+ return adoptRef(new StorageEvent);
+}
+
+StorageEvent::StorageEvent()
+{
+}
+
+StorageEvent::~StorageEvent()
+{
+}
+
+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_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& url, Storage* storageArea)
+{
+ if (dispatched())
+ return;
+
+ initEvent(type, canBubble, cancelable);
+
+ m_key = key;
+ m_oldValue = oldValue;
+ m_newValue = newValue;
+ m_url = url;
+ m_storageArea = storageArea;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageEvent.h b/Source/WebCore/storage/StorageEvent.h
new file mode 100644
index 0000000..8e558a8
--- /dev/null
+++ b/Source/WebCore/storage/StorageEvent.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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 INC. ``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 INC. 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 StorageEvent_h
+#define StorageEvent_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "Event.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ class Storage;
+
+ 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& 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& 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& 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 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& url, Storage* storageArea);
+
+ String m_key;
+ String m_oldValue;
+ String m_newValue;
+ String m_url;
+ RefPtr<Storage> m_storageArea;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageEvent_h
diff --git a/Source/WebCore/storage/StorageEvent.idl b/Source/WebCore/storage/StorageEvent.idl
new file mode 100644
index 0000000..3464caa
--- /dev/null
+++ b/Source/WebCore/storage/StorageEvent.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008, 2009 Apple 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 INC. ``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 INC. 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=DOM_STORAGE
+ ] StorageEvent : Event {
+ readonly attribute [ConvertNullStringTo=Null] DOMString key;
+ readonly attribute [ConvertNullStringTo=Null] DOMString oldValue;
+ readonly attribute [ConvertNullStringTo=Null] DOMString newValue;
+ 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 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 urlArg, in Storage storageAreaArg);
+ };
+
+}
diff --git a/Source/WebCore/storage/StorageEventDispatcher.cpp b/Source/WebCore/storage/StorageEventDispatcher.cpp
new file mode 100644
index 0000000..e662b03
--- /dev/null
+++ b/Source/WebCore/storage/StorageEventDispatcher.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageEventDispatcher.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "DOMWindow.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "SecurityOrigin.h"
+#include "StorageEvent.h"
+
+namespace WebCore {
+
+void StorageEventDispatcher::dispatch(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Frame* sourceFrame)
+{
+#ifdef ANDROID
+ if (!sourceFrame)
+ return;
+#endif
+ Page* page = sourceFrame->page();
+ if (!page)
+ return;
+
+ // We need to copy all relevant frames from every page to a vector since sending the event to one frame might mutate the frame tree
+ // of any given page in the group or mutate the page group itself.
+ Vector<RefPtr<Frame> > frames;
+ if (storageType == SessionStorage) {
+ // Send events only to our page.
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
+ frames.append(frame);
+ }
+
+ for (unsigned i = 0; i < frames.size(); ++i) {
+ ExceptionCode ec = 0;
+ Storage* storage = frames[i]->domWindow()->sessionStorage(ec);
+ if (!ec)
+ frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
+ }
+ } else {
+ // Send events to every page.
+ const HashSet<Page*>& pages = page->group().pages();
+ HashSet<Page*>::const_iterator end = pages.end();
+ for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
+ frames.append(frame);
+ }
+ }
+
+ for (unsigned i = 0; i < frames.size(); ++i) {
+ ExceptionCode ec = 0;
+ Storage* storage = frames[i]->domWindow()->localStorage(ec);
+ if (!ec)
+ frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
+ }
+ }
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageEventDispatcher.h b/Source/WebCore/storage/StorageEventDispatcher.h
new file mode 100644
index 0000000..f4a98ef
--- /dev/null
+++ b/Source/WebCore/storage/StorageEventDispatcher.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 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 StorageEventDispatcher_h
+#define StorageEventDispatcher_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+#include "StorageArea.h"
+
+namespace WebCore {
+
+ // This is in its own class since Chromium must override it.
+ class StorageEventDispatcher {
+ public:
+ static void dispatch(const String& key, const String& oldValue, const String& newValue, StorageType, SecurityOrigin*, Frame* sourceFrame);
+
+ private:
+ // Do not instantiate.
+ StorageEventDispatcher();
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageEventDispatcher_h
diff --git a/Source/WebCore/storage/StorageMap.cpp b/Source/WebCore/storage/StorageMap.cpp
new file mode 100644
index 0000000..790fde2
--- /dev/null
+++ b/Source/WebCore/storage/StorageMap.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageMap.h"
+
+#if ENABLE(DOM_STORAGE)
+
+namespace WebCore {
+
+PassRefPtr<StorageMap> StorageMap::create(unsigned quota)
+{
+ return adoptRef(new StorageMap(quota));
+}
+
+StorageMap::StorageMap(unsigned quota)
+ : m_iterator(m_map.end())
+ , m_iteratorIndex(UINT_MAX)
+ , m_quotaSize(quota) // quota measured in bytes
+ , m_currentLength(0)
+{
+}
+
+PassRefPtr<StorageMap> StorageMap::copy()
+{
+ RefPtr<StorageMap> newMap = create(m_quotaSize);
+ newMap->m_map = m_map;
+ newMap->m_currentLength = m_currentLength;
+ return newMap.release();
+}
+
+void StorageMap::invalidateIterator()
+{
+ m_iterator = m_map.end();
+ m_iteratorIndex = UINT_MAX;
+}
+
+void StorageMap::setIteratorToIndex(unsigned index)
+{
+ // FIXME: Once we have bidirectional iterators for HashMap we can be more intelligent about this.
+ // The requested index will be closest to begin(), our current iterator, or end(), and we
+ // can take the shortest route.
+ // Until that mechanism is available, we'll always increment our iterator from begin() or current.
+
+ if (m_iteratorIndex == index)
+ return;
+
+ if (index < m_iteratorIndex) {
+ m_iteratorIndex = 0;
+ m_iterator = m_map.begin();
+ ASSERT(m_iterator != m_map.end());
+ }
+
+ while (m_iteratorIndex < index) {
+ ++m_iteratorIndex;
+ ++m_iterator;
+ ASSERT(m_iterator != m_map.end());
+ }
+}
+
+unsigned StorageMap::length() const
+{
+ return m_map.size();
+}
+
+String StorageMap::key(unsigned index)
+{
+ if (index >= length())
+ return String();
+
+ setIteratorToIndex(index);
+ return m_iterator->first;
+}
+
+String StorageMap::getItem(const String& key) const
+{
+ return m_map.get(key);
+}
+
+PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue, bool& quotaException)
+{
+ ASSERT(!value.isNull());
+ quotaException = false;
+
+ // Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects
+ // so if more than one Storage object refs this map, copy it before mutating it.
+ if (refCount() > 1) {
+ RefPtr<StorageMap> newStorageMap = copy();
+ newStorageMap->setItem(key, value, oldValue, quotaException);
+ return newStorageMap.release();
+ }
+
+ // Quota tracking. This is done in a couple of steps to keep the overflow tracking simple.
+ unsigned newLength = m_currentLength;
+ bool overflow = newLength + value.length() < newLength;
+ newLength += value.length();
+
+ oldValue = m_map.get(key);
+ overflow |= newLength - oldValue.length() > newLength;
+ newLength -= oldValue.length();
+
+ unsigned adjustedKeyLength = oldValue.isNull() ? key.length() : 0;
+ overflow |= newLength + adjustedKeyLength < newLength;
+ newLength += adjustedKeyLength;
+
+ ASSERT(!overflow); // Overflow is bad...even if quotas are off.
+ bool overQuota = newLength > m_quotaSize / sizeof(UChar);
+ if (m_quotaSize != noQuota && (overflow || overQuota)) {
+ quotaException = true;
+ return 0;
+ }
+ m_currentLength = newLength;
+
+ pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
+ if (!addResult.second)
+ addResult.first->second = value;
+
+ invalidateIterator();
+
+ return 0;
+}
+
+PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValue)
+{
+ // Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects
+ // so if more than one Storage object refs this map, copy it before mutating it.
+ if (refCount() > 1) {
+ RefPtr<StorageMap> newStorage = copy();
+ newStorage->removeItem(key, oldValue);
+ return newStorage.release();
+ }
+
+ oldValue = m_map.take(key);
+ if (!oldValue.isNull()) {
+ invalidateIterator();
+ ASSERT(m_currentLength - key.length() <= m_currentLength);
+ m_currentLength -= key.length();
+ }
+ ASSERT(m_currentLength - oldValue.length() <= m_currentLength);
+ m_currentLength -= oldValue.length();
+
+ return 0;
+}
+
+bool StorageMap::contains(const String& key) const
+{
+ return m_map.contains(key);
+}
+
+void StorageMap::importItem(const String& key, const String& value)
+{
+ // Be sure to copy the keys/values as items imported on a background thread are destined
+ // to cross a thread boundary
+ pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.threadsafeCopy(), value.threadsafeCopy());
+ ASSERT(result.second); // True if the key didn't exist previously.
+
+ ASSERT(m_currentLength + key.length() >= m_currentLength);
+ m_currentLength += key.length();
+ ASSERT(m_currentLength + value.length() >= m_currentLength);
+ m_currentLength += value.length();
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageMap.h b/Source/WebCore/storage/StorageMap.h
new file mode 100644
index 0000000..cc09d0f
--- /dev/null
+++ b/Source/WebCore/storage/StorageMap.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageMap_h
+#define StorageMap_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+ class StorageMap : public RefCounted<StorageMap> {
+ public:
+ // Quota size measured in bytes.
+ static PassRefPtr<StorageMap> create(unsigned quotaSize);
+
+ unsigned length() const;
+ String key(unsigned index);
+ String getItem(const String&) const;
+ PassRefPtr<StorageMap> setItem(const String& key, const String& value, String& oldValue, bool& quota_exception);
+ PassRefPtr<StorageMap> removeItem(const String&, String& oldValue);
+
+ bool contains(const String& key) const;
+
+ void importItem(const String& key, const String& value);
+
+ unsigned quota() const { return m_quotaSize; }
+
+ static const unsigned noQuota = UINT_MAX;
+
+ private:
+ StorageMap(unsigned quota);
+ PassRefPtr<StorageMap> copy();
+ void invalidateIterator();
+ void setIteratorToIndex(unsigned);
+
+ HashMap<String, String> m_map;
+ HashMap<String, String>::iterator m_iterator;
+ unsigned m_iteratorIndex;
+
+ unsigned m_quotaSize; // Measured in bytes.
+ unsigned m_currentLength; // Measured in UChars.
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageMap_h
diff --git a/Source/WebCore/storage/StorageNamespace.cpp b/Source/WebCore/storage/StorageNamespace.cpp
new file mode 100644
index 0000000..ce36608
--- /dev/null
+++ b/Source/WebCore/storage/StorageNamespace.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageNamespace.h"
+
+#include "StorageNamespaceImpl.h"
+
+#if PLATFORM(CHROMIUM)
+#error "Chromium should not compile this file and instead define its own version of these factories that navigate the multi-process boundry."
+#endif
+
+#if ENABLE(DOM_STORAGE)
+
+namespace WebCore {
+
+PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const String& path, unsigned quota)
+{
+ return StorageNamespaceImpl::localStorageNamespace(path, quota);
+}
+
+// The page argument is only used by the Chromium port.
+PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*, unsigned quota)
+{
+ return StorageNamespaceImpl::sessionStorageNamespace(quota);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageNamespace.h b/Source/WebCore/storage/StorageNamespace.h
new file mode 100644
index 0000000..f7dad1e
--- /dev/null
+++ b/Source/WebCore/storage/StorageNamespace.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageNamespace_h
+#define StorageNamespace_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Page;
+class SecurityOrigin;
+class StorageArea;
+
+// This interface is required for Chromium since these actions need to be proxied between processes.
+class StorageNamespace : public RefCounted<StorageNamespace> {
+public:
+ static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
+ static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*, unsigned quota);
+
+ virtual ~StorageNamespace() { }
+ virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0;
+ virtual PassRefPtr<StorageNamespace> copy() = 0;
+ virtual void close() = 0;
+ virtual void unlock() = 0;
+
+#ifdef ANDROID
+ virtual void clear(Page*) = 0;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageNamespace_h
diff --git a/Source/WebCore/storage/StorageNamespaceImpl.cpp b/Source/WebCore/storage/StorageNamespaceImpl.cpp
new file mode 100644
index 0000000..68508a7
--- /dev/null
+++ b/Source/WebCore/storage/StorageNamespaceImpl.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageNamespaceImpl.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "SecurityOriginHash.h"
+#include "StorageAreaImpl.h"
+#include "StorageMap.h"
+#include "StorageSyncManager.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#ifdef ANDROID
+#include "Page.h"
+#endif
+
+namespace WebCore {
+
+typedef HashMap<String, StorageNamespace*> LocalStorageNamespaceMap;
+
+static LocalStorageNamespaceMap& localStorageNamespaceMap()
+{
+ DEFINE_STATIC_LOCAL(LocalStorageNamespaceMap, localStorageNamespaceMap, ());
+ return localStorageNamespaceMap;
+}
+
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path, unsigned quota)
+{
+ const String lookupPath = path.isNull() ? String("") : path;
+ LocalStorageNamespaceMap::iterator it = localStorageNamespaceMap().find(lookupPath);
+ if (it == localStorageNamespaceMap().end()) {
+ RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota));
+ localStorageNamespaceMap().set(lookupPath, storageNamespace.get());
+ return storageNamespace.release();
+ }
+
+ return it->second;
+}
+
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(unsigned quota)
+{
+ return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), quota));
+}
+
+StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota)
+ : m_storageType(storageType)
+ , m_path(path.crossThreadString())
+ , m_syncManager(0)
+ , m_quota(quota)
+ , m_isShutdown(false)
+{
+ if (m_storageType == LocalStorage && !m_path.isEmpty())
+ m_syncManager = StorageSyncManager::create(m_path);
+}
+
+StorageNamespaceImpl::~StorageNamespaceImpl()
+{
+ ASSERT(isMainThread());
+
+ if (m_storageType == LocalStorage) {
+ ASSERT(localStorageNamespaceMap().get(m_path) == this);
+ localStorageNamespaceMap().remove(m_path);
+ }
+
+ if (!m_isShutdown)
+ close();
+}
+
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_isShutdown);
+ ASSERT(m_storageType == SessionStorage);
+
+ RefPtr<StorageNamespaceImpl> newNamespace = adoptRef(new StorageNamespaceImpl(m_storageType, m_path, m_quota));
+
+ StorageAreaMap::iterator end = m_storageAreaMap.end();
+ for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i)
+ newNamespace->m_storageAreaMap.set(i->first, i->second->copy());
+ return newNamespace.release();
+}
+
+PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin)
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_isShutdown);
+
+ RefPtr<SecurityOrigin> origin = prpOrigin;
+ RefPtr<StorageAreaImpl> storageArea;
+ if ((storageArea = m_storageAreaMap.get(origin)))
+ return storageArea.release();
+
+ storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota);
+ m_storageAreaMap.set(origin.release(), storageArea);
+ return storageArea.release();
+}
+
+void StorageNamespaceImpl::close()
+{
+ ASSERT(isMainThread());
+
+ if (m_isShutdown)
+ return;
+
+ // If we're session storage, we shouldn't need to do any work here.
+ if (m_storageType == SessionStorage) {
+ ASSERT(!m_syncManager);
+ return;
+ }
+
+ StorageAreaMap::iterator end = m_storageAreaMap.end();
+ for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it)
+ it->second->close();
+
+ if (m_syncManager)
+ m_syncManager->close();
+
+ m_isShutdown = true;
+}
+
+#ifdef ANDROID
+void StorageNamespaceImpl::clear(Page* page)
+{
+ ASSERT(isMainThread());
+ if (m_isShutdown)
+ return;
+
+ // Clear all the keys for each of the storage areas.
+ StorageAreaMap::iterator end = m_storageAreaMap.end();
+ for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) {
+ // if there is no page provided, then the user tried to clear storage
+ // with only pages in private browsing mode open. So we do not need to
+ // provide a Frame* here (as the frame is only used to dispatch storage events
+ // and private browsing pages won't be using them).
+ it->second->clear(page ? page->mainFrame() : 0);
+ }
+}
+#endif
+
+void StorageNamespaceImpl::unlock()
+{
+ // Because there's a single event loop per-process, this is a no-op.
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/Source/WebCore/storage/StorageNamespaceImpl.h b/Source/WebCore/storage/StorageNamespaceImpl.h
new file mode 100644
index 0000000..c2361fa
--- /dev/null
+++ b/Source/WebCore/storage/StorageNamespaceImpl.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageNamespaceImpl_h
+#define StorageNamespaceImpl_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+#include "SecurityOriginHash.h"
+#include "StorageArea.h"
+#include "StorageNamespace.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+#ifdef ANDROID
+ class Page;
+#endif
+ class StorageAreaImpl;
+
+ class StorageNamespaceImpl : public StorageNamespace {
+ public:
+ static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
+ static PassRefPtr<StorageNamespace> sessionStorageNamespace(unsigned quota);
+
+ virtual ~StorageNamespaceImpl();
+ virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>);
+ virtual PassRefPtr<StorageNamespace> copy();
+ virtual void close();
+ virtual void unlock();
+
+#ifdef ANDROID
+ virtual void clear(Page*);
+#endif
+
+ private:
+ StorageNamespaceImpl(StorageType, const String& path, unsigned quota);
+
+ typedef HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageAreaImpl>, SecurityOriginHash> StorageAreaMap;
+ StorageAreaMap m_storageAreaMap;
+
+ StorageType m_storageType;
+
+ // Only used if m_storageType == LocalStorage and the path was not "" in our constructor.
+ String m_path;
+ RefPtr<StorageSyncManager> m_syncManager;
+
+ unsigned m_quota; // The default quota for each new storage area.
+ bool m_isShutdown;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageNamespaceImpl_h
diff --git a/Source/WebCore/storage/StorageSyncManager.cpp b/Source/WebCore/storage/StorageSyncManager.cpp
new file mode 100644
index 0000000..1cf8306
--- /dev/null
+++ b/Source/WebCore/storage/StorageSyncManager.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 "StorageSyncManager.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "EventNames.h"
+#include "FileSystem.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "LocalStorageTask.h"
+#include "LocalStorageThread.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "StorageAreaSync.h"
+#include <wtf/text/CString.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+PassRefPtr<StorageSyncManager> StorageSyncManager::create(const String& path)
+{
+ return adoptRef(new StorageSyncManager(path));
+}
+
+StorageSyncManager::StorageSyncManager(const String& path)
+ : m_thread(LocalStorageThread::create())
+ , m_path(path.crossThreadString())
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_path.isEmpty());
+ m_thread->start();
+}
+
+StorageSyncManager::~StorageSyncManager()
+{
+ ASSERT(isMainThread());
+ ASSERT(!m_thread);
+}
+
+// Called on a background thread.
+String StorageSyncManager::fullDatabaseFilename(const String& databaseIdentifier)
+{
+ if (!makeAllDirectories(m_path)) {
+ LOG_ERROR("Unabled to create LocalStorage database path %s", m_path.utf8().data());
+ return String();
+ }
+
+ return pathByAppendingComponent(m_path, databaseIdentifier + ".localstorage");
+}
+
+void StorageSyncManager::close()
+{
+ ASSERT(isMainThread());
+
+ if (m_thread) {
+ m_thread->terminate();
+ m_thread = 0;
+ }
+}
+
+bool StorageSyncManager::scheduleImport(PassRefPtr<StorageAreaSync> area)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_thread);
+ if (m_thread)
+ m_thread->scheduleTask(LocalStorageTask::createImport(area.get()));
+ return m_thread;
+}
+
+void StorageSyncManager::scheduleSync(PassRefPtr<StorageAreaSync> area)
+{
+ ASSERT(isMainThread());
+ ASSERT(m_thread);
+ if (m_thread)
+ 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/Source/WebCore/storage/StorageSyncManager.h b/Source/WebCore/storage/StorageSyncManager.h
new file mode 100644
index 0000000..6fbb75d
--- /dev/null
+++ b/Source/WebCore/storage/StorageSyncManager.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 Apple 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 INC. ``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 INC. 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 StorageSyncManager_h
+#define StorageSyncManager_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+ class LocalStorageThread;
+ class SecurityOrigin;
+ class StorageAreaSync;
+
+ class StorageSyncManager : public RefCounted<StorageSyncManager> {
+ public:
+ static PassRefPtr<StorageSyncManager> create(const String& path);
+ ~StorageSyncManager();
+
+ bool scheduleImport(PassRefPtr<StorageAreaSync>);
+ void scheduleSync(PassRefPtr<StorageAreaSync>);
+ void scheduleDeleteEmptyDatabase(PassRefPtr<StorageAreaSync>);
+
+ void close();
+
+ private:
+ StorageSyncManager(const String& path);
+
+ OwnPtr<LocalStorageThread> m_thread;
+
+ // The following members are subject to thread synchronization issues
+ public:
+ // To be called from the background thread:
+ String fullDatabaseFilename(const String& databaseIdentifier);
+
+ private:
+ String m_path;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageSyncManager_h
diff --git a/Source/WebCore/storage/chromium/DatabaseObserver.h b/Source/WebCore/storage/chromium/DatabaseObserver.h
new file mode 100644
index 0000000..deb8036
--- /dev/null
+++ b/Source/WebCore/storage/chromium/DatabaseObserver.h
@@ -0,0 +1,57 @@
+/*
+ * 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 DatabaseObserver_h
+#define DatabaseObserver_h
+
+#if ENABLE(DATABASE)
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class AbstractDatabase;
+class ScriptExecutionContext;
+
+// The implementation of this class is in the WebKit API (Chromium source tree)
+// in WebKit/chromium/src/DatabaseObserver.cpp.
+class DatabaseObserver {
+public:
+ 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/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp b/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
new file mode 100644
index 0000000..361e203
--- /dev/null
+++ b/Source/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
@@ -0,0 +1,208 @@
+/*
+ * 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 "DatabaseTracker.h"
+
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
+#include "DatabaseObserver.h"
+#include "QuotaTracker.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "SecurityOriginHash.h"
+#include "SQLiteFileSystem.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+DatabaseTracker& DatabaseTracker::tracker()
+{
+ DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, (""));
+ return tracker;
+}
+
+DatabaseTracker::DatabaseTracker(const String&)
+{
+ SQLiteFileSystem::registerSQLiteVFS();
+}
+
+bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* scriptExecutionContext, const String& name, const String& displayName, unsigned long estimatedSize)
+{
+ return DatabaseObserver::canEstablishDatabase(scriptExecutionContext, name, displayName, estimatedSize);
+}
+
+void DatabaseTracker::setDatabaseDetails(SecurityOrigin*, const String&, const String&, unsigned long)
+{
+ // Chromium sets the database details when the database is opened
+}
+
+String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool)
+{
+ return origin->databaseIdentifier() + "/" + name + "#";
+}
+
+void DatabaseTracker::addOpenDatabase(AbstractDatabase* database)
+{
+ ASSERT(database->scriptExecutionContext()->isContextThread());
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ if (!m_openDatabaseMap)
+ m_openDatabaseMap.set(new DatabaseOriginMap());
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
+ if (!nameMap) {
+ nameMap = new DatabaseNameMap();
+ m_openDatabaseMap->set(database->securityOrigin(), nameMap);
+ }
+
+ String name(database->stringIdentifier());
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet) {
+ databaseSet = new DatabaseSet();
+ nameMap->set(name, databaseSet);
+ }
+
+ databaseSet->add(database);
+
+ DatabaseObserver::databaseOpened(database);
+}
+
+class TrackerRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<AbstractDatabase> database)
+ {
+ return new TrackerRemoveOpenDatabaseTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
+ }
+
+private:
+ TrackerRemoveOpenDatabaseTask(PassRefPtr<AbstractDatabase> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<AbstractDatabase> m_database;
+};
+
+void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database)
+{
+ if (!database->scriptExecutionContext()->isContextThread()) {
+ database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database));
+ return;
+ }
+
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ ASSERT(m_openDatabaseMap);
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin());
+ ASSERT(nameMap);
+ String name(database->stringIdentifier());
+ DatabaseSet* databaseSet = nameMap->get(name);
+ ASSERT(databaseSet);
+ databaseSet->remove(database);
+
+ if (databaseSet->isEmpty()) {
+ nameMap->remove(name);
+ delete databaseSet;
+ if (nameMap->isEmpty()) {
+ m_openDatabaseMap->remove(database->securityOrigin());
+ delete nameMap;
+ }
+ }
+
+ DatabaseObserver::databaseClosed(database);
+}
+
+
+void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases)
+{
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+ if (!m_openDatabaseMap)
+ return;
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
+ if (!nameMap)
+ return;
+
+ DatabaseSet* databaseSet = nameMap->get(name);
+ if (!databaseSet)
+ return;
+
+ for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
+ databases->add(*it);
+}
+
+unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
+{
+ unsigned long long spaceAvailable = 0;
+ unsigned long long databaseSize = 0;
+ QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin(
+ database->securityOrigin()->databaseIdentifier(),
+ database->stringIdentifier(), &databaseSize, &spaceAvailable);
+ return databaseSize + spaceAvailable;
+}
+
+void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
+{
+ Vector<RefPtr<AbstractDatabase> > openDatabases;
+ {
+ MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+ if (!m_openDatabaseMap)
+ return;
+
+ DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin());
+ if (!nameMap)
+ return;
+
+ DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
+ for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
+ DatabaseSet* databaseSet = dbNameMapIt->second;
+ DatabaseSet::const_iterator dbSetEndIt = databaseSet->end();
+ for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) {
+ if ((*dbSetIt)->scriptExecutionContext() == context)
+ openDatabases.append(*dbSetIt);
+ }
+ }
+ }
+
+ Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesEndIt = openDatabases.end();
+ for (Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt)
+ (*openDatabasesIt)->interrupt();
+}
+
+}
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/chromium/IDBFactoryBackendInterface.cpp b/Source/WebCore/storage/chromium/IDBFactoryBackendInterface.cpp
new file mode 100644
index 0000000..c0fb444
--- /dev/null
+++ b/Source/WebCore/storage/chromium/IDBFactoryBackendInterface.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 "IDBFactoryBackendInterface.h"
+
+#include "ChromiumBridge.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+PassRefPtr<IDBFactoryBackendInterface> IDBFactoryBackendInterface::create()
+{
+ return ChromiumBridge::idbFactory();
+}
+
+IDBFactoryBackendInterface::~IDBFactoryBackendInterface()
+{
+ ChromiumBridge::idbShutdown();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp b/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp
new file mode 100644
index 0000000..0f10875
--- /dev/null
+++ b/Source/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "IDBKeyPathBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "ChromiumBridge.h"
+
+namespace WebCore {
+
+void IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(const Vector<RefPtr<SerializedScriptValue>, 0>& values, const String& keyPath, Vector<RefPtr<IDBKey>, 0>& keys)
+{
+ ChromiumBridge::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/storage/chromium/QuotaTracker.cpp b/Source/WebCore/storage/chromium/QuotaTracker.cpp
new file mode 100644
index 0000000..3f48682
--- /dev/null
+++ b/Source/WebCore/storage/chromium/QuotaTracker.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 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 "QuotaTracker.h"
+
+#if ENABLE(DATABASE)
+
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+QuotaTracker& QuotaTracker::instance()
+{
+ DEFINE_STATIC_LOCAL(QuotaTracker, tracker, ());
+ return tracker;
+}
+
+void QuotaTracker::getDatabaseSizeAndSpaceAvailableToOrigin(
+ const String& originIdentifier, const String& databaseName,
+ unsigned long long* databaseSize, unsigned long long* spaceAvailable)
+{
+ MutexLocker lockData(m_dataGuard);
+ ASSERT(m_databaseSizes.contains(originIdentifier));
+ HashMap<String, SizeMap>::const_iterator it = m_databaseSizes.find(originIdentifier);
+ ASSERT(it->second.contains(databaseName));
+ *databaseSize = it->second.get(databaseName);
+
+ ASSERT(m_spaceAvailableToOrigins.contains(originIdentifier));
+ *spaceAvailable = m_spaceAvailableToOrigins.get(originIdentifier);
+}
+
+void QuotaTracker::updateDatabaseSizeAndSpaceAvailableToOrigin(
+ const String& originIdentifier, const String& databaseName,
+ unsigned long long databaseSize, unsigned long long spaceAvailable)
+{
+ MutexLocker lockData(m_dataGuard);
+ m_spaceAvailableToOrigins.set(originIdentifier, spaceAvailable);
+ HashMap<String, SizeMap>::iterator it = m_databaseSizes.add(originIdentifier, SizeMap()).first;
+ it->second.set(databaseName, databaseSize);
+}
+
+}
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/chromium/QuotaTracker.h b/Source/WebCore/storage/chromium/QuotaTracker.h
new file mode 100644
index 0000000..774475e
--- /dev/null
+++ b/Source/WebCore/storage/chromium/QuotaTracker.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 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 QuotaTracker_h
+#define QuotaTracker_h
+
+#if ENABLE(DATABASE)
+
+#include "PlatformString.h"
+#include "SecurityOrigin.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class QuotaTracker {
+public:
+ static QuotaTracker& instance();
+
+ void getDatabaseSizeAndSpaceAvailableToOrigin(
+ const String& originIdentifier, const String& databaseName,
+ unsigned long long* databaseSize, unsigned long long* spaceAvailable);
+ void updateDatabaseSizeAndSpaceAvailableToOrigin(
+ const String& originIdentifier, const String& databaseName,
+ unsigned long long databaseSize, unsigned long long spaceAvailable);
+
+private:
+ QuotaTracker() { }
+
+ typedef HashMap<String, unsigned long long> SizeMap;
+ SizeMap m_spaceAvailableToOrigins;
+ HashMap<String, SizeMap> m_databaseSizes;
+ Mutex m_dataGuard;
+};
+
+}
+
+#endif // ENABLE(DATABASE)
+
+#endif // QuotaTracker_h
diff --git a/Source/WebCore/storage/chromium/SQLTransactionClientChromium.cpp b/Source/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
new file mode 100644
index 0000000..6a10821
--- /dev/null
+++ b/Source/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 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 "SQLTransactionClient.h"
+
+#if ENABLE(DATABASE)
+
+#include "AbstractDatabase.h"
+#include "DatabaseObserver.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+class NotifyDatabaseChangedTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<NotifyDatabaseChangedTask> create(AbstractDatabase *database)
+ {
+ return new NotifyDatabaseChangedTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ WebCore::DatabaseObserver::databaseModified(m_database.get());
+ }
+
+private:
+ NotifyDatabaseChangedTask(PassRefPtr<AbstractDatabase> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<AbstractDatabase> m_database;
+};
+
+void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database)
+{
+ if (!database->scriptExecutionContext()->isContextThread()) {
+ database->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(database));
+ return;
+ }
+
+ WebCore::DatabaseObserver::databaseModified(database);
+}
+
+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.
+}
+
+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(database->scriptExecutionContext()->isContextThread());
+ return false;
+}
+
+}
+
+#endif // ENABLE(DATABASE)
diff --git a/Source/WebCore/storage/wince/DatabaseThreadWinCE.cpp b/Source/WebCore/storage/wince/DatabaseThreadWinCE.cpp
new file mode 100644
index 0000000..d81145d
--- /dev/null
+++ b/Source/WebCore/storage/wince/DatabaseThreadWinCE.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, 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 library is distributed in the hope that i will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "DatabaseThread.h"
+
+#include "Database.h"
+#include "DatabaseTask.h"
+
+namespace WebCore {
+
+DatabaseThread::DatabaseThread()
+: m_timer(this, &DatabaseThread::timerFired)
+{
+}
+
+DatabaseThread::~DatabaseThread()
+{
+}
+
+void DatabaseThread::requestTermination()
+{
+ m_queue.clear();
+}
+
+bool DatabaseThread::terminationRequested() const
+{
+ return m_queue.isEmpty();
+}
+
+void DatabaseThread::timerFired(Timer<DatabaseThread>*)
+{
+ if (!m_queue.isEmpty()) {
+ RefPtr<DatabaseTask> task = m_queue.first();
+ task->performTask();
+ m_queue.removeFirst();
+ if (!m_queue.isEmpty())
+ m_timer.startOneShot(0);
+ }
+}
+
+void DatabaseThread::scheduleTask(PassRefPtr<DatabaseTask> task)
+{
+ m_queue.append(task);
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void DatabaseThread::scheduleImmediateTask(PassRefPtr<DatabaseTask> task)
+{
+ task->performTask();
+}
+
+void DatabaseThread::unscheduleDatabaseTasks(Database* database)
+{
+ Deque<RefPtr<DatabaseTask> > reservedTasks;
+ for (Deque<RefPtr<DatabaseTask> >::const_iterator i = m_queue.begin(); i != m_queue.end(); ++i) {
+ if ((*i)->database() != database)
+ reservedTasks.append(*i);
+ }
+
+ m_queue.swap(reservedTasks);
+}
+
+void DatabaseThread::recordDatabaseOpen(Database* database)
+{
+ notImplemented();
+}
+
+void DatabaseThread::recordDatabaseClosed(Database* database)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/storage/wince/DatabaseThreadWinCE.h b/Source/WebCore/storage/wince/DatabaseThreadWinCE.h
new file mode 100644
index 0000000..1921cc1
--- /dev/null
+++ b/Source/WebCore/storage/wince/DatabaseThreadWinCE.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, 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 library is distributed in the hope that i will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef DatabaseThreadWinCE_h
+#define DatabaseThreadWinCE_h
+
+#include <wtf/Deque.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Database;
+ class DatabaseTask;
+
+ class DatabaseThread: public WTF::RefCounted<DatabaseThread> {
+
+ public:
+ static PassRefPtr<DatabaseThread> create() { return adoptRef(new DatabaseThread); }
+ ~DatabaseThread();
+
+ bool start() { return true; }
+ void requestTermination();
+ bool terminationRequested() const;
+
+ void scheduleTask(PassRefPtr<DatabaseTask>);
+ void scheduleImmediateTask(PassRefPtr<DatabaseTask>);
+ void unscheduleDatabaseTasks(Database*);
+ void recordDatabaseOpen(Database*);
+ void recordDatabaseClosed(Database*);
+#ifndef NDEBUG
+ ThreadIdentifier getThreadID() const { return currentThread(); }
+#endif
+
+ private:
+ DatabaseThread();
+
+ void timerFired(Timer<DatabaseThread>*);
+
+ Deque<RefPtr<DatabaseTask> > m_queue;
+ Timer<DatabaseThread> m_timer;
+ };
+
+} // namespace WebCore
+
+#endif // DatabaseThreadWinCE_h
diff --git a/Source/WebCore/storage/wince/LocalStorageThreadWinCE.cpp b/Source/WebCore/storage/wince/LocalStorageThreadWinCE.cpp
new file mode 100644
index 0000000..90c4e89
--- /dev/null
+++ b/Source/WebCore/storage/wince/LocalStorageThreadWinCE.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, 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 library is distributed in the hope that i will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "LocalStorageThread.h"
+
+#include "LocalStorageTask.h"
+#include "StorageAreaSync.h"
+
+namespace WebCore {
+
+LocalStorageThread::LocalStorageThread()
+: m_timer(this, &LocalStorageThread::timerFired)
+{
+}
+
+LocalStorageThread::~LocalStorageThread()
+{
+}
+
+bool LocalStorageThread::start()
+{
+ return true;
+}
+
+void LocalStorageThread::timerFired(Timer<LocalStorageThread>*)
+{
+ if (!m_queue.isEmpty()) {
+ RefPtr<LocalStorageTask> task = m_queue.first();
+ task->performTask();
+ m_queue.removeFirst();
+ if (!m_queue.isEmpty())
+ m_timer.startOneShot(0);
+ }
+}
+
+void LocalStorageThread::scheduleImport(PassRefPtr<StorageAreaSync> area)
+{
+ m_queue.append(LocalStorageTask::createImport(area));
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void LocalStorageThread::scheduleSync(PassRefPtr<StorageAreaSync> area)
+{
+ m_queue.append(LocalStorageTask::createSync(area));
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void LocalStorageThread::terminate()
+{
+ m_queue.clear();
+ m_timer.stop();
+}
+
+void LocalStorageThread::performTerminate()
+{
+ m_queue.clear();
+ m_timer.stop();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/storage/wince/LocalStorageThreadWinCE.h b/Source/WebCore/storage/wince/LocalStorageThreadWinCE.h
new file mode 100644
index 0000000..06e7d45
--- /dev/null
+++ b/Source/WebCore/storage/wince/LocalStorageThreadWinCE.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Torch Mobile, 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 library is distributed in the hope that i will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef LocalStorageThreadWinCE_h
+#define LocalStorageThreadWinCE_h
+
+#include <wtf/Deque.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+ class StorageAreaSync;
+ class LocalStorageTask;
+
+ class LocalStorageThread : public RefCounted<LocalStorageThread> {
+ public:
+ static PassRefPtr<LocalStorageThread> create() { return adoptRef(new LocalStorageThread); }
+
+ ~LocalStorageThread();
+ bool start();
+ void scheduleImport(PassRefPtr<StorageAreaSync>);
+ void scheduleSync(PassRefPtr<StorageAreaSync>);
+ void terminate();
+ void performTerminate();
+
+ private:
+ LocalStorageThread();
+
+ void timerFired(Timer<LocalStorageThread>*);
+
+ Deque<RefPtr<LocalStorageTask> > m_queue;
+ Timer<LocalStorageThread> m_timer;
+ };
+
+} // namespace WebCore
+
+#endif // LocalStorageThreadWinCE_h