diff options
Diffstat (limited to 'WebCore/storage')
194 files changed, 10969 insertions, 1297 deletions
diff --git a/WebCore/storage/AbstractDatabase.cpp b/WebCore/storage/AbstractDatabase.cpp new file mode 100644 index 0000000..8d3bf1e --- /dev/null +++ b/WebCore/storage/AbstractDatabase.cpp @@ -0,0 +1,490 @@ +/* + * 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/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(); +} + +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/WebCore/storage/AbstractDatabase.h b/WebCore/storage/AbstractDatabase.h new file mode 100644 index 0000000..3d8d363 --- /dev/null +++ b/WebCore/storage/AbstractDatabase.h @@ -0,0 +1,131 @@ +/* + * 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(); + bool lastActionChangedDatabase(); + bool lastActionWasInsert(); + void resetDeletes(); + bool hadDeletes(); + void resetAuthorizer(); + + virtual void markAsDeletedAndClose() = 0; + virtual void closeImmediately() = 0; + +protected: + AbstractDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion, + const String& displayName, unsigned long estimatedSize); + + void closeDatabase(); + + virtual bool performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec); + + static const String& databaseInfoTableName(); + + RefPtr<ScriptExecutionContext> m_scriptExecutionContext; + RefPtr<SecurityOrigin> m_contextThreadSecurityOrigin; + + String m_name; + String m_expectedVersion; + String m_displayName; + unsigned long m_estimatedSize; + String m_filename; + +#ifndef NDEBUG + String databaseDebugName() const { return m_contextThreadSecurityOrigin->toString() + "::" + m_name; } +#endif + +private: + static const String& databaseVersionKey(); + + int m_guid; + bool m_opened; + bool m_new; + + SQLiteDatabase m_sqliteDatabase; + + RefPtr<DatabaseAuthorizer> m_databaseAuthorizer; +}; + +} // namespace WebCore + +#endif // ENABLE(DATABASE) + +#endif // AbstractDatabase_h diff --git a/WebCore/storage/ChangeVersionWrapper.cpp b/WebCore/storage/ChangeVersionWrapper.cpp index 17a9407..17be716 100644 --- a/WebCore/storage/ChangeVersionWrapper.cpp +++ b/WebCore/storage/ChangeVersionWrapper.cpp @@ -30,6 +30,9 @@ #if ENABLE(DATABASE) #include "Database.h" +#include "SQLError.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> namespace WebCore { @@ -47,13 +50,13 @@ bool ChangeVersionWrapper::performPreflight(SQLTransaction* transaction) if (!transaction->database()->getVersionFromDatabase(actualVersion)) { LOG_ERROR("Unable to retrieve actual current version from database"); - m_sqlError = SQLError::create(0, "unable to verify current version of database"); + m_sqlError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to verify current version of database"); return false; } if (actualVersion != m_oldVersion) { LOG_ERROR("Old version doesn't match actual version"); - m_sqlError = SQLError::create(2, "current version of the database and `oldVersion` argument do not match"); + m_sqlError = SQLError::create(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match"); return false; } @@ -66,7 +69,7 @@ bool ChangeVersionWrapper::performPostflight(SQLTransaction* transaction) if (!transaction->database()->setVersionInDatabase(m_newVersion)) { LOG_ERROR("Unable to set new version in database"); - m_sqlError = SQLError::create(0, "unable to set new version in database"); + m_sqlError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to set new version in database"); return false; } diff --git a/WebCore/storage/ChangeVersionWrapper.h b/WebCore/storage/ChangeVersionWrapper.h index b14fe55..86cc182 100644 --- a/WebCore/storage/ChangeVersionWrapper.h +++ b/WebCore/storage/ChangeVersionWrapper.h @@ -32,9 +32,12 @@ #include "PlatformString.h" #include "SQLTransaction.h" +#include <wtf/Forward.h> namespace WebCore { +class SQLError; + class ChangeVersionWrapper : public SQLTransactionWrapper { public: static PassRefPtr<ChangeVersionWrapper> create(const String& oldVersion, const String& newVersion) { return adoptRef(new ChangeVersionWrapper(oldVersion, newVersion)); } diff --git a/WebCore/storage/DOMFilePath.cpp b/WebCore/storage/DOMFilePath.cpp new file mode 100644 index 0000000..2da057c --- /dev/null +++ b/WebCore/storage/DOMFilePath.cpp @@ -0,0 +1,166 @@ +/* + * 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 "DOMFilePath.h" + +#if ENABLE(FILE_SYSTEM) + +#include "RegularExpression.h" +#include <wtf/Vector.h> +#include <wtf/text/CString.h> + +namespace WebCore { + +const char DOMFilePath::separator = '/'; +const char DOMFilePath::root[] = "/"; + +String DOMFilePath::append(const String& base, const String& components) +{ + return ensureDirectoryPath(base) + components; +} + +String DOMFilePath::ensureDirectoryPath(const String& path) +{ + if (!DOMFilePath::endsWithSeparator(path)) { + String newPath = path; + newPath.append(DOMFilePath::separator); + return newPath; + } + return path; +} + +String DOMFilePath::getName(const String& path) +{ + int index = path.reverseFind(DOMFilePath::separator); + if (index != -1) + return path.substring(index); + return path; +} + +String DOMFilePath::getDirectory(const String& path) +{ + int index = path.reverseFind(DOMFilePath::separator); + if (index == 0) + return DOMFilePath::root; + if (index != -1) + return path.substring(0, index); + return "."; +} + +bool DOMFilePath::isParentOf(const String& parent, const String& mayBeChild) +{ + ASSERT(DOMFilePath::isAbsolute(parent)); + ASSERT(DOMFilePath::isAbsolute(mayBeChild)); + if (parent == DOMFilePath::root && mayBeChild != DOMFilePath::root) + return true; + if (parent.length() >= mayBeChild.length() || !mayBeChild.startsWith(parent, false)) + return false; + if (mayBeChild[parent.length()] != DOMFilePath::separator) + return false; + return true; +} + +String DOMFilePath::removeExtraParentReferences(const String& path) +{ + ASSERT(DOMFilePath::isAbsolute(path)); + Vector<String> components; + Vector<String> canonicalized; + path.split(DOMFilePath::separator, components); + for (size_t i = 0; i < components.size(); ++i) { + if (components[i] == ".") + continue; + if (components[i] == "..") { + if (canonicalized.size() > 0) + canonicalized.removeLast(); + continue; + } + canonicalized.append(components[i]); + } + if (canonicalized.isEmpty()) + return DOMFilePath::root; + String result; + for (size_t i = 0; i < canonicalized.size(); ++i) { + result.append(DOMFilePath::separator); + result.append(canonicalized[i]); + } + return result; +} + +// Check the naming restrictions defined in FileSystem API 8.3. +// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions +bool DOMFilePath::isValidPath(const String& path) +{ + if (path.isEmpty() || path == DOMFilePath::root) + return true; + + // Chars 0-31 in UTF-8 prepresentation are not allowed. + for (size_t i = 0; i < path.length(); ++i) + if (path[i] < 32) + return false; + + // Unallowed names. + DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp1, ("(/|^)(CON|PRN|AUX|NUL)([\\./]|$)", TextCaseInsensitive)); + DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp2, ("(/|^)(COM|LPT)[1-9]([\\./]|$)", TextCaseInsensitive)); + + if (unallowedNamesRegExp1.match(path) >= 0) + return false; + if (unallowedNamesRegExp2.match(path) >= 0) + return false; + + // Names must not end with period or whitespace. + DEFINE_STATIC_LOCAL(RegularExpression, endingRegExp, ("[\\.\\s](/|$)", TextCaseInsensitive)); + + if (endingRegExp.match(path) >= 0) + return false; + + // Unallowed chars: '\', '<', '>', ':', '?', '*', '"', '|' + // (We don't check '/' here as this method takes paths as its argument.) + DEFINE_STATIC_LOCAL(RegularExpression, unallowedCharsRegExp, ("[\\\\<>:\\?\\*\"|]", TextCaseInsensitive)); + + if (unallowedCharsRegExp.match(path) >= 0) + return false; + + return true; +} + +bool DOMFilePath::isValidName(const String& name) +{ + if (name.isEmpty()) + return true; + // '/' is not allowed in name. + if (name.contains('/')) + return false; + return isValidPath(name); +} + +} // namespace WebCore + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/DOMFilePath.h b/WebCore/storage/DOMFilePath.h new file mode 100644 index 0000000..2f2bb23 --- /dev/null +++ b/WebCore/storage/DOMFilePath.h @@ -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: + * + * * 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 DOMFilePath_h +#define DOMFilePath_h + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +// DOMFileSystem path utilities. All methods in this class are static. +class DOMFilePath { +public: + static const char separator; + static const char root[]; + + // Returns the name part from the given path. + static String getName(const String& path); + + // Returns the parent directory path of the given path. + static String getDirectory(const String& path); + + // Checks if a given path is a parent of mayBeChild. This method assumes given paths are absolute and do not have extra references to a parent (i.e. "../"). + static bool isParentOf(const String& path, const String& mayBeChild); + + // Appends the separator at the end of the path if it's not there already. + static String ensureDirectoryPath(const String& path); + + // Returns a new path by appending a separator and the supplied path component to the path. + static String append(const String& path, const String& component); + + static bool isAbsolute(const String& path) + { + return path.startsWith(DOMFilePath::root); + } + + static bool endsWithSeparator(const String& path) + { + return path[path.length() - 1] == DOMFilePath::separator; + } + + // Evaluates all "../" and "./" segments. Note that "/../" expands to "/", so you can't ever refer to anything above the root directory. + static String removeExtraParentReferences(const String& path); + + // Checks if the given path follows the FileSystem API naming restrictions. + static bool isValidPath(const String& path); + + // Checks if the given name follows the FileSystem API naming restrictions. + static bool isValidName(const String& name); + +private: + DOMFilePath() { } +}; + +} // namespace WebCore + +#endif // DOMFilePath_h diff --git a/WebCore/storage/DOMFileSystem.cpp b/WebCore/storage/DOMFileSystem.cpp new file mode 100644 index 0000000..c3dbd34 --- /dev/null +++ b/WebCore/storage/DOMFileSystem.cpp @@ -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. + */ + +#include "config.h" +#include "DOMFileSystem.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DirectoryEntry.h" + +namespace WebCore { + +DOMFileSystem::DOMFileSystem(const String& name, const String& rootPath) + : m_rootPath(rootPath) + , m_name(name) +{ +} + +PassRefPtr<DirectoryEntry> DOMFileSystem::root() +{ + return DirectoryEntry::create(this, "/"); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/DOMFileSystem.h b/WebCore/storage/DOMFileSystem.h new file mode 100644 index 0000000..b87aaaf --- /dev/null +++ b/WebCore/storage/DOMFileSystem.h @@ -0,0 +1,65 @@ +/* + * 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 DOMFileSystem_h +#define DOMFileSystem_h + +#if ENABLE(FILE_SYSTEM) + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class DirectoryEntry; + +class DOMFileSystem : public RefCounted<DOMFileSystem> { +public: + static PassRefPtr<DOMFileSystem> create(const String& name, const String& rootPath) + { + return adoptRef(new DOMFileSystem(name, rootPath)); + } + + const String& name() const { return m_name; } + PassRefPtr<DirectoryEntry> root(); + +private: + DOMFileSystem(const String& name, const String& rootPath); + + String m_rootPath; + String m_name; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // DOMFileSystem_h diff --git a/WebCore/storage/DOMFileSystem.idl b/WebCore/storage/DOMFileSystem.idl new file mode 100644 index 0000000..b7307e2 --- /dev/null +++ b/WebCore/storage/DOMFileSystem.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=FILE_SYSTEM + ] DOMFileSystem { + readonly attribute DOMString name; + readonly attribute DirectoryEntry root; + }; +} diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp index 2130631..089f9ee 100644 --- a/WebCore/storage/Database.cpp +++ b/WebCore/storage/Database.cpp @@ -29,32 +29,31 @@ #include "config.h" #include "Database.h" -#include <wtf/StdLibExtras.h> - #if ENABLE(DATABASE) #include "ChangeVersionWrapper.h" -#include "CString.h" -#include "DatabaseAuthorizer.h" +#include "DatabaseCallback.h" #include "DatabaseTask.h" #include "DatabaseThread.h" #include "DatabaseTracker.h" #include "Document.h" -#include "ExceptionCode.h" -#include "Frame.h" #include "InspectorController.h" #include "Logging.h" #include "NotImplemented.h" #include "Page.h" -#include "OriginQuotaManager.h" -#include "ScriptController.h" -#include "SQLiteDatabase.h" -#include "SQLiteFileSystem.h" -#include "SQLiteStatement.h" -#include "SQLResultSet.h" +#include "SQLTransactionCallback.h" #include "SQLTransactionClient.h" #include "SQLTransactionCoordinator.h" - -#endif // ENABLE(DATABASE) +#include "SQLTransactionErrorCallback.h" +#include "SQLiteStatement.h" +#include "ScriptController.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include "VoidCallback.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/StdLibExtras.h> #if USE(JSC) #include "JSDOMWindow.h" @@ -62,89 +61,43 @@ namespace WebCore { -// If we sleep for more the 30 seconds while blocked on SQLITE_BUSY, give up. -static const int maxSqliteBusyWaitTime = 30000; - -const String& Database::databaseInfoTableName() -{ - DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__")); - return name; -} - -#if ENABLE(DATABASE) - -static bool isDatabaseAvailable = true; - -void Database::setIsAvailable(bool available) -{ - isDatabaseAvailable = available; -} - -bool Database::isAvailable() -{ - return isDatabaseAvailable; -} - -static Mutex& guidMutex() -{ - // Note: We don't have to use AtomicallyInitializedStatic here because - // this function is called once in the constructor on the main thread - // before any other threads that call this function are used. - DEFINE_STATIC_LOCAL(Mutex, mutex, ()); - return mutex; -} - -typedef HashMap<int, String> GuidVersionMap; -static GuidVersionMap& guidToVersionMap() -{ - DEFINE_STATIC_LOCAL(GuidVersionMap, map, ()); - return map; -} - -// NOTE: Caller must lock guidMutex(). -static inline void updateGuidVersionMap(int guid, String newVersion) -{ - // Ensure the the mutex is locked. - ASSERT(!guidMutex().tryLock()); - - // Note: It is not safe to put an empty string into the guidToVersionMap() map. - // That's because the map is cross-thread, but empty strings are per-thread. - // The copy() function makes a version of the string you can use on the current - // thread, but we need a string we can keep in a cross-thread data structure. - // FIXME: This is a quite-awkward restriction to have to program with. - - // Map null string to empty string (see comment above). - guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.threadsafeCopy()); -} +class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task { +public: + static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> creationCallback) + { + return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback)); + } -typedef HashMap<int, HashSet<Database*>*> GuidDatabaseMap; -static GuidDatabaseMap& guidToDatabaseMap() -{ - DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ()); - return map; -} + virtual void performTask(ScriptExecutionContext*) + { + m_creationCallback->handleEvent(m_database.get()); + } -static const String& databaseVersionKey() -{ - DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey")); - return key; -} +private: + DatabaseCreationCallbackTask(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> callback) + : m_database(database) + , m_creationCallback(callback) + { + } -static int guidForOriginAndName(const String& origin, const String& name); + RefPtr<Database> m_database; + RefPtr<DatabaseCallback> m_creationCallback; +}; -PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e) +PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name, + const String& expectedVersion, const String& displayName, + unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, + ExceptionCode& e) { if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) { - // FIXME: There should be an exception raised here in addition to returning a null Database object. The question has been raised with the WHATWG. LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data()); return 0; } RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize)); - if (!database->openAndVerifyVersion(e)) { + if (!database->openAndVerifyVersion(!creationCallback, e)) { LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data()); - context->removeOpenDatabase(database.get()); DatabaseTracker::tracker().removeOpenDatabase(database.get()); return 0; } @@ -156,182 +109,92 @@ PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, con if (context->isDocument()) { Document* document = static_cast<Document*>(context); if (Page* page = document->page()) - page->inspectorController()->didOpenDatabase(database.get(), context->securityOrigin()->host(), name, expectedVersion); + 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) - : m_transactionInProgress(false) + : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize) + , m_transactionInProgress(false) , m_isTransactionQueueEnabled(true) - , m_scriptExecutionContext(context) - , m_name(name.crossThreadString()) - , m_guid(0) - , m_expectedVersion(expectedVersion.crossThreadString()) - , m_displayName(displayName.crossThreadString()) - , m_estimatedSize(estimatedSize) , m_deleted(false) - , m_stopped(false) - , m_opened(false) { - ASSERT(m_scriptExecutionContext.get()); - m_mainThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin(); - m_databaseThreadSecurityOrigin = m_mainThreadSecurityOrigin->threadsafeCopy(); - if (m_name.isNull()) - m_name = ""; + m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->threadsafeCopy(); ScriptController::initializeThreading(); - - m_guid = guidForOriginAndName(securityOrigin()->toString(), name); - - { - MutexLocker locker(guidMutex()); - - HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid); - if (!hashSet) { - hashSet = new HashSet<Database*>; - guidToDatabaseMap().set(m_guid, hashSet); - } - - hashSet->add(this); - } - ASSERT(m_scriptExecutionContext->databaseThread()); - m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name); - - DatabaseTracker::tracker().addOpenDatabase(this); - context->addOpenDatabase(this); } class DerefContextTask : public ScriptExecutionContext::Task { public: - static PassOwnPtr<DerefContextTask> create() + static PassOwnPtr<DerefContextTask> create(PassRefPtr<ScriptExecutionContext> context) { - return new DerefContextTask(); + return adoptPtr(new DerefContextTask(context)); } virtual void performTask(ScriptExecutionContext* context) { - context->deref(); + ASSERT_UNUSED(context, context == m_context); + m_context.clear(); } virtual bool isCleanupTask() const { return true; } + +private: + DerefContextTask(PassRefPtr<ScriptExecutionContext> context) + : m_context(context) + { + } + + RefPtr<ScriptExecutionContext> m_context; }; Database::~Database() { // The reference to the ScriptExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing. if (!m_scriptExecutionContext->isContextThread()) { - m_scriptExecutionContext->postTask(DerefContextTask::create()); - m_scriptExecutionContext.release().releaseRef(); + // Grab a pointer to the script execution here because we're releasing it when we pass it to + // DerefContextTask::create. + ScriptExecutionContext* scriptExecutionContext = m_scriptExecutionContext.get(); + + scriptExecutionContext->postTask(DerefContextTask::create(m_scriptExecutionContext.release())); } } -bool Database::openAndVerifyVersion(ExceptionCode& e) +String Database::version() const { - if (!m_scriptExecutionContext->databaseThread()) - return false; - m_databaseAuthorizer = DatabaseAuthorizer::create(); + if (m_deleted) + return String(); + return AbstractDatabase::version(); +} - bool success = false; +bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode& e) +{ DatabaseTaskSynchronizer synchronizer; - OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success); + 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; } - -static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString) -{ - SQLiteStatement statement(db, query); - int result = statement.prepare(); - - if (result != SQLResultOk) { - LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data()); - return false; - } - - result = statement.step(); - if (result == SQLResultRow) { - resultString = statement.getColumnText(0); - return true; - } else if (result == SQLResultDone) { - resultString = String(); - return true; - } else { - LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data()); - return false; - } -} - -bool Database::getVersionFromDatabase(String& version) -{ - DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';")); - - m_databaseAuthorizer->disable(); - - bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version); - if (!result) - LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data()); - - m_databaseAuthorizer->enable(); - - return result; -} - -static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value) -{ - SQLiteStatement statement(db, query); - int result = statement.prepare(); - - if (result != SQLResultOk) { - LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data()); - return false; - } - - statement.bindText(1, value); - - result = statement.step(); - if (result != SQLResultDone) { - LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data()); - return false; - } - - return true; -} - -bool Database::setVersionInDatabase(const String& version) -{ - // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE - // clause in the CREATE statement (see Database::performOpenAndVerify()). - DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoTableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);")); - - m_databaseAuthorizer->disable(); - - bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version); - if (!result) - LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data()); - - m_databaseAuthorizer->enable(); - - return result; -} - -bool Database::versionMatchesExpected() const -{ - if (!m_expectedVersion.isEmpty()) { - MutexLocker locker(guidMutex()); - return m_expectedVersion == guidToVersionMap().get(m_guid); - } - - return true; -} - void Database::markAsDeletedAndClose() { if (m_deleted || !m_scriptExecutionContext->databaseThread()) @@ -340,262 +203,95 @@ void Database::markAsDeletedAndClose() LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this); m_deleted = true; - if (m_scriptExecutionContext->databaseThread()->terminationRequested()) { + 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; } - m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this); - - DatabaseTaskSynchronizer synchronizer; OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer); - m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release()); synchronizer.waitForTaskCompletion(); } -class ContextRemoveOpenDatabaseTask : public ScriptExecutionContext::Task { -public: - static PassOwnPtr<ContextRemoveOpenDatabaseTask> create(PassRefPtr<Database> database) - { - return new ContextRemoveOpenDatabaseTask(database); - } - - virtual void performTask(ScriptExecutionContext* context) - { - context->removeOpenDatabase(m_database.get()); - DatabaseTracker::tracker().removeOpenDatabase(m_database.get()); - } - - virtual bool isCleanupTask() const { return true; } - -private: - ContextRemoveOpenDatabaseTask(PassRefPtr<Database> database) - : m_database(database) - { - } - - RefPtr<Database> m_database; -}; - void Database::close() { - RefPtr<Database> protect = this; - - if (!m_opened) - return; - ASSERT(m_scriptExecutionContext->databaseThread()); ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID()); - m_sqliteDatabase.close(); - // Must ref() before calling databaseThread()->recordDatabaseClosed(). - m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this); - m_opened = false; - - { - MutexLocker locker(guidMutex()); - - HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid); - ASSERT(hashSet); - ASSERT(hashSet->contains(this)); - hashSet->remove(this); - if (hashSet->isEmpty()) { - guidToDatabaseMap().remove(m_guid); - delete hashSet; - guidToVersionMap().remove(m_guid); - } - } - - m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this); - m_scriptExecutionContext->postTask(ContextRemoveOpenDatabaseTask::create(this)); -} - -void Database::stop() -{ - // FIXME: The net effect of the following code is to remove all pending transactions and statements, but allow the current statement - // to run to completion. In the future we can use the sqlite3_progress_handler or sqlite3_interrupt interfaces to cancel the current - // statement in response to close(), as well. - - // This method is meant to be used as an analog to cancelling a loader, and is used when a document is shut down as the result of - // a page load or closing the page - m_stopped = true; { MutexLocker locker(m_transactionInProgressMutex); m_isTransactionQueueEnabled = false; m_transactionInProgress = false; } -} -unsigned long long Database::maximumSize() const -{ - return DatabaseTracker::tracker().getMaxSizeForDatabase(this); -} + closeDatabase(); -void Database::disableAuthorizer() -{ - ASSERT(m_databaseAuthorizer); - m_databaseAuthorizer->disable(); + // 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::enableAuthorizer() +void Database::closeImmediately() { - ASSERT(m_databaseAuthorizer); - m_databaseAuthorizer->enable(); + DatabaseThread* databaseThread = scriptExecutionContext()->databaseThread(); + if (databaseThread && !databaseThread->terminationRequested() && opened()) + databaseThread->scheduleImmediateTask(DatabaseCloseTask::create(this, 0)); } -void Database::setAuthorizerReadOnly() +unsigned long long Database::maximumSize() const { - ASSERT(m_databaseAuthorizer); - m_databaseAuthorizer->setReadOnly(); + return DatabaseTracker::tracker().getMaxSizeForDatabase(this); } -static int guidForOriginAndName(const String& origin, const String& name) +bool Database::performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode& e) { - String stringID; - if (origin.endsWith("/")) - stringID = origin + name; - else - stringID = origin + "/" + name; - - // Note: We don't have to use AtomicallyInitializedStatic here because - // this function is called once in the constructor on the main thread - // before any other threads that call this function are used. - DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ()); - MutexLocker locker(stringIdentifierMutex); - typedef HashMap<String, int> IDGuidMap; - DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ()); - int guid = stringIdentifierToGUIDMap.get(stringID); - if (!guid) { - static int currentNewGUID = 1; - guid = currentNewGUID++; - stringIdentifierToGUIDMap.set(stringID, guid); + if (AbstractDatabase::performOpenAndVerify(setVersionInNewDatabase, e)) { + if (m_scriptExecutionContext->databaseThread()) + m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this); + + return true; } - return guid; + return false; } -void Database::resetAuthorizer() +void Database::changeVersion(const String& oldVersion, const String& newVersion, + PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, + PassRefPtr<VoidCallback> successCallback) { - if (m_databaseAuthorizer) - m_databaseAuthorizer->reset(); + m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion))); + MutexLocker locker(m_transactionInProgressMutex); + if (!m_transactionInProgress) + scheduleTransaction(); } -void Database::performPolicyChecks() +void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback) { - // FIXME: Code similar to the following will need to be run to enforce the per-origin size limit the spec mandates. - // Additionally, we might need a way to pause the database thread while the UA prompts the user for permission to - // increase the size limit - - /* - if (m_databaseAuthorizer->lastActionIncreasedSize()) - DatabaseTracker::scheduleFileSizeCheckOnMainThread(this); - */ - - notImplemented(); + runTransaction(callback, errorCallback, successCallback, false); } -bool Database::performOpenAndVerify(ExceptionCode& e) +void Database::readTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback) { - if (!m_sqliteDatabase.open(m_filename)) { - LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data()); - e = INVALID_STATE_ERR; - return false; - } - - ASSERT(m_databaseAuthorizer); - m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer); - m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); - - String currentVersion; - { - MutexLocker locker(guidMutex()); - - GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid); - if (entry != guidToVersionMap().end()) { - // Map null string to empty string (see updateGuidVersionMap()). - currentVersion = entry->second.isNull() ? String("") : entry->second; - LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data()); - } else { - LOG(StorageAPI, "No cached version for guid %i", m_guid); - - if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) { - if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) { - LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data()); - e = INVALID_STATE_ERR; - // Close the handle to the database file. - m_sqliteDatabase.close(); - return false; - } - } - - if (!getVersionFromDatabase(currentVersion)) { - LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data()); - e = INVALID_STATE_ERR; - // Close the handle to the database file. - m_sqliteDatabase.close(); - return false; - } - if (currentVersion.length()) { - LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data()); - } else { - LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data()); - if (!setVersionInDatabase(m_expectedVersion)) { - LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data()); - e = INVALID_STATE_ERR; - // Close the handle to the database file. - m_sqliteDatabase.close(); - return false; - } - currentVersion = m_expectedVersion; - } - - updateGuidVersionMap(m_guid, currentVersion); - } - } - - if (currentVersion.isNull()) { - LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data()); - currentVersion = ""; - } - - // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception. - // If the expected version is the empty string, then we always return with whatever version of the database we have. - if (m_expectedVersion.length() && m_expectedVersion != currentVersion) { - LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(), - databaseDebugName().ascii().data(), currentVersion.ascii().data()); - e = INVALID_STATE_ERR; - // Close the handle to the database file. - m_sqliteDatabase.close(); - return false; - } - - // All checks passed and we still have a handle to this database file. - // Make sure DatabaseThread closes it when DatabaseThread goes away. - m_opened = true; - if (m_scriptExecutionContext->databaseThread()) - m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this); - - return true; + runTransaction(callback, errorCallback, successCallback, true); } -void Database::changeVersion(const String& oldVersion, const String& newVersion, - PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, - PassRefPtr<VoidCallback> successCallback) +void Database::runTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, + PassRefPtr<VoidCallback> successCallback, bool readOnly) { - m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, ChangeVersionWrapper::create(oldVersion, newVersion))); + m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly)); MutexLocker locker(m_transactionInProgressMutex); if (!m_transactionInProgress) scheduleTransaction(); } -void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, - PassRefPtr<VoidCallback> successCallback, bool readOnly) +void Database::inProgressTransactionCompleted() { - m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly)); MutexLocker locker(m_transactionInProgressMutex); - if (!m_transactionInProgress) - scheduleTransaction(); + m_transactionInProgress = false; + scheduleTransaction(); } void Database::scheduleTransaction() @@ -604,8 +300,7 @@ void Database::scheduleTransaction() RefPtr<SQLTransaction> transaction; if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) { - transaction = m_transactionQueue.first(); - m_transactionQueue.removeFirst(); + transaction = m_transactionQueue.takeFirst(); } if (transaction && m_scriptExecutionContext->databaseThread()) { @@ -634,7 +329,7 @@ class DeliverPendingCallbackTask : public ScriptExecutionContext::Task { public: static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction) { - return new DeliverPendingCallbackTask(transaction); + return adoptPtr(new DeliverPendingCallbackTask(transaction)); } virtual void performTask(ScriptExecutionContext*) @@ -660,7 +355,7 @@ Vector<String> Database::performGetTableNames() { disableAuthorizer(); - SQLiteStatement statement(m_sqliteDatabase, "SELECT name FROM sqlite_master WHERE type='table';"); + SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';"); if (statement.prepare() != SQLResultOk) { LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data()); enableAuthorizer(); @@ -695,71 +390,31 @@ SQLTransactionCoordinator* Database::transactionCoordinator() const return m_scriptExecutionContext->databaseThread()->transactionCoordinator(); } -String Database::version() const -{ - if (m_deleted) - return String(); - MutexLocker locker(guidMutex()); - return guidToVersionMap().get(m_guid).threadsafeCopy(); -} - Vector<String> Database::tableNames() { // FIXME: Not using threadsafeCopy on these strings looks ok since threads take strict turns // in dealing with them. However, if the code changes, this may not be true anymore. Vector<String> result; - if (!m_scriptExecutionContext->databaseThread()) + DatabaseTaskSynchronizer synchronizer; + if (!m_scriptExecutionContext->databaseThread() || m_scriptExecutionContext->databaseThread()->terminationRequested(&synchronizer)) return result; - DatabaseTaskSynchronizer synchronizer; OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result); - m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release()); synchronizer.waitForTaskCompletion(); return result; } -void Database::setExpectedVersion(const String& version) -{ - m_expectedVersion = version.threadsafeCopy(); - // Update the in memory database version map. - MutexLocker locker(guidMutex()); - updateGuidVersionMap(m_guid, version); -} - SecurityOrigin* Database::securityOrigin() const { - if (scriptExecutionContext()->isContextThread()) - return m_mainThreadSecurityOrigin.get(); + if (m_scriptExecutionContext->isContextThread()) + return m_contextThreadSecurityOrigin.get(); if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID()) return m_databaseThreadSecurityOrigin.get(); return 0; } -String Database::stringIdentifier() const -{ - // Return a deep copy for ref counting thread safety - return m_name.threadsafeCopy(); -} - -String Database::displayName() const -{ - // Return a deep copy for ref counting thread safety - return m_displayName.threadsafeCopy(); -} - -unsigned long Database::estimatedSize() const -{ - return m_estimatedSize; -} - -String Database::fileName() const -{ - // Return a deep copy for ref counting thread safety - return m_filename.threadsafeCopy(); -} +} // namespace WebCore #endif // ENABLE(DATABASE) - -} // namespace WebCore diff --git a/WebCore/storage/Database.h b/WebCore/storage/Database.h index 0d7f33c..47001a4 100644 --- a/WebCore/storage/Database.h +++ b/WebCore/storage/Database.h @@ -30,154 +30,91 @@ #define Database_h #if ENABLE(DATABASE) +#include "AbstractDatabase.h" +#include "ExceptionCode.h" #include "PlatformString.h" -#include "SecurityOrigin.h" -#include "SQLiteDatabase.h" -#include "SQLTransaction.h" -#include "StringHash.h" -#include "Timer.h" -#include "VoidCallback.h" -#include <wtf/Forward.h> -#include <wtf/HashSet.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> #include <wtf/Deque.h> -#else -#include "PlatformString.h" -#endif +#include <wtf/Forward.h> -#if ENABLE(DATABASE) namespace WebCore { -class DatabaseAuthorizer; -class DatabaseThread; +class DatabaseCallback; class ScriptExecutionContext; -class SQLResultSet; +class SecurityOrigin; +class SQLTransaction; class SQLTransactionCallback; class SQLTransactionClient; class SQLTransactionCoordinator; class SQLTransactionErrorCallback; -class SQLValue; - -typedef int ExceptionCode; +class VoidCallback; -class Database : public ThreadSafeShared<Database> { - friend class DatabaseTransactionTask; - friend class SQLStatement; - friend class SQLTransaction; +class Database : public AbstractDatabase { public: - static void setIsAvailable(bool); - static bool isAvailable(); - - ~Database(); - -// Direct support for the DOM API - static PassRefPtr<Database> openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&); - String version() const; - void changeVersion(const String& oldVersion, const String& newVersion, - PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, - PassRefPtr<VoidCallback> successCallback); - void transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, - PassRefPtr<VoidCallback> successCallback, bool readOnly); - -// Internal engine support - static const String& databaseInfoTableName(); - - void disableAuthorizer(); - void enableAuthorizer(); - void setAuthorizerReadOnly(); - + 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(); - ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); } - SecurityOrigin* securityOrigin() const; - String stringIdentifier() const; - String displayName() const; - unsigned long estimatedSize() const; - String fileName() const; - - bool getVersionFromDatabase(String&); - bool setVersionInDatabase(const String&); - void setExpectedVersion(const String&); - bool versionMatchesExpected() const; + virtual SecurityOrigin* securityOrigin() const; - void markAsDeletedAndClose(); + virtual void markAsDeletedAndClose(); bool deleted() const { return m_deleted; } void close(); - bool opened() const { return m_opened; } - - void stop(); - bool stopped() const { return m_stopped; } + virtual void closeImmediately(); unsigned long long databaseSize() const; unsigned long long maximumSize() const; -// Called from DatabaseThread, must be prepared to work on the background thread - void resetAuthorizer(); - void performPolicyChecks(); - - bool performOpenAndVerify(ExceptionCode&); - - Vector<String> performGetTableNames(); + void scheduleTransactionCallback(SQLTransaction*); + void scheduleTransactionStep(SQLTransaction*, bool immediately = false); SQLTransactionClient* transactionClient() const; SQLTransactionCoordinator* transactionCoordinator() const; private: - Database(ScriptExecutionContext* context, const String& name, - const String& expectedVersion, const String& displayName, - unsigned long estimatedSize); + class DatabaseOpenTask; + class DatabaseCloseTask; + class DatabaseTransactionTask; + class DatabaseTableNamesTask; + + Database(ScriptExecutionContext*, const String& name, const String& expectedVersion, + const String& displayName, unsigned long estimatedSize); + void runTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, + PassRefPtr<VoidCallback> successCallback, bool readOnly); - bool openAndVerifyVersion(ExceptionCode&); + bool openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode&); + virtual bool performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode&); + void inProgressTransactionCompleted(); void scheduleTransaction(); - void scheduleTransactionCallback(SQLTransaction*); - void scheduleTransactionStep(SQLTransaction* transaction, bool immediately = false); + + Vector<String> performGetTableNames(); + + static void deliverPendingCallback(void*); Deque<RefPtr<SQLTransaction> > m_transactionQueue; Mutex m_transactionInProgressMutex; bool m_transactionInProgress; bool m_isTransactionQueueEnabled; - static void deliverPendingCallback(void*); - - RefPtr<ScriptExecutionContext> m_scriptExecutionContext; - RefPtr<SecurityOrigin> m_mainThreadSecurityOrigin; RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin; - String m_name; - int m_guid; - String m_expectedVersion; - String m_displayName; - unsigned long m_estimatedSize; - String m_filename; bool m_deleted; - - bool m_stopped; - - bool m_opened; - - SQLiteDatabase m_sqliteDatabase; - RefPtr<DatabaseAuthorizer> m_databaseAuthorizer; - -#ifndef NDEBUG - String databaseDebugName() const { return m_mainThreadSecurityOrigin->toString() + "::" + m_name; } -#endif }; } // namespace WebCore -#else - -namespace WebCore { -class Database : public ThreadSafeShared<Database> { -public: - static const String& databaseInfoTableName(); -}; -} // namespace WebCore - #endif // ENABLE(DATABASE) #endif // Database_h diff --git a/WebCore/storage/Database.idl b/WebCore/storage/Database.idl index c8a537c..20c2fa1 100644 --- a/WebCore/storage/Database.idl +++ b/WebCore/storage/Database.idl @@ -30,12 +30,13 @@ module storage { interface [ Conditional=DATABASE, - OmitConstructor + OmitConstructor, + NoStaticTables ] Database { readonly attribute DOMString version; - [Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback); - [Custom] void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback); - [Custom] void readTransaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback); + [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/WebCore/storage/DatabaseAuthorizer.cpp b/WebCore/storage/DatabaseAuthorizer.cpp index d87d4d9..79e47d4 100644 --- a/WebCore/storage/DatabaseAuthorizer.cpp +++ b/WebCore/storage/DatabaseAuthorizer.cpp @@ -29,13 +29,19 @@ #include "config.h" #include "DatabaseAuthorizer.h" -#include "Database.h" #include "PlatformString.h" +#include <wtf/PassRefPtr.h> namespace WebCore { -DatabaseAuthorizer::DatabaseAuthorizer() +PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName) +{ + return adoptRef(new DatabaseAuthorizer(databaseInfoTableName)); +} + +DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName) : m_securityEnabled(false) + , m_databaseInfoTableName(databaseInfoTableName) { reset(); addWhitelistedFunctions(); @@ -48,6 +54,11 @@ void DatabaseAuthorizer::reset() m_readOnly = false; } +void DatabaseAuthorizer::resetDeletes() +{ + m_hadDeletes = false; +} + void DatabaseAuthorizer::addWhitelistedFunctions() { // SQLite functions used to help implement some operations @@ -102,6 +113,7 @@ void DatabaseAuthorizer::addWhitelistedFunctions() m_whitelistedFunctions.add("total"); // SQLite FTS functions + m_whitelistedFunctions.add("match"); m_whitelistedFunctions.add("snippet"); m_whitelistedFunctions.add("offsets"); m_whitelistedFunctions.add("optimize"); @@ -136,7 +148,7 @@ int DatabaseAuthorizer::dropTable(const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::dropTempTable(const String& tableName) @@ -147,7 +159,7 @@ int DatabaseAuthorizer::dropTempTable(const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::allowAlterTable(const String&, const String& tableName) @@ -184,7 +196,7 @@ int DatabaseAuthorizer::dropIndex(const String&, const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName) @@ -195,7 +207,7 @@ int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::createTrigger(const String&, const String& tableName) @@ -223,7 +235,7 @@ int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName) @@ -234,7 +246,7 @@ int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::createView(const String&) @@ -252,7 +264,11 @@ int DatabaseAuthorizer::createTempView(const String&) int DatabaseAuthorizer::dropView(const String&) { - return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow); + if (m_readOnly && m_securityEnabled) + return SQLAuthDeny; + + m_hadDeletes = true; + return SQLAuthAllow; } int DatabaseAuthorizer::dropTempView(const String&) @@ -260,24 +276,36 @@ int DatabaseAuthorizer::dropTempView(const String&) // SQLITE_DROP_TEMP_VIEW results in a DELETE operation, which is not // allowed in read-only transactions or private browsing, so we might as // well disallow SQLITE_DROP_TEMP_VIEW in these cases - return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow); + if (m_readOnly && m_securityEnabled) + return SQLAuthDeny; + + m_hadDeletes = true; + return SQLAuthAllow; } -int DatabaseAuthorizer::createVTable(const String&, const String&) +int DatabaseAuthorizer::createVTable(const String& tableName, const String& moduleName) { if (m_readOnly && m_securityEnabled) return SQLAuthDeny; + // Allow only the FTS3 extension + if (!equalIgnoringCase(moduleName, "fts3")) + return SQLAuthDeny; + m_lastActionChangedDatabase = true; - return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; + return denyBasedOnTableName(tableName); } -int DatabaseAuthorizer::dropVTable(const String&, const String&) +int DatabaseAuthorizer::dropVTable(const String& tableName, const String& moduleName) { if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return m_securityEnabled ? SQLAuthDeny : SQLAuthAllow; + // Allow only the FTS3 extension + if (!equalIgnoringCase(moduleName, "fts3")) + return SQLAuthDeny; + + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::allowDelete(const String& tableName) @@ -285,7 +313,7 @@ int DatabaseAuthorizer::allowDelete(const String& tableName) if (m_readOnly && m_securityEnabled) return SQLAuthDeny; - return denyBasedOnTableName(tableName); + return updateDeletesBasedOnTableName(tableName); } int DatabaseAuthorizer::allowInsert(const String& tableName) @@ -365,7 +393,7 @@ void DatabaseAuthorizer::setReadOnly() m_readOnly = true; } -int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) +int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const { if (!m_securityEnabled) return SQLAuthAllow; @@ -376,10 +404,18 @@ int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) // equalIgnoringCase(tableName, "sqlite_sequence") || equalIgnoringCase(tableName, Database::databaseInfoTableName())) // return SQLAuthDeny; - if (equalIgnoringCase(tableName, Database::databaseInfoTableName())) + if (equalIgnoringCase(tableName, m_databaseInfoTableName)) return SQLAuthDeny; return SQLAuthAllow; } +int DatabaseAuthorizer::updateDeletesBasedOnTableName(const String& tableName) +{ + int allow = denyBasedOnTableName(tableName); + if (allow) + m_hadDeletes = true; + return allow; +} + } // namespace WebCore diff --git a/WebCore/storage/DatabaseAuthorizer.h b/WebCore/storage/DatabaseAuthorizer.h index 037409e..e7c3922 100644 --- a/WebCore/storage/DatabaseAuthorizer.h +++ b/WebCore/storage/DatabaseAuthorizer.h @@ -28,22 +28,21 @@ #ifndef DatabaseAuthorizer_h #define DatabaseAuthorizer_h -#include "StringHash.h" +#include "PlatformString.h" +#include <wtf/Forward.h> #include <wtf/HashSet.h> -#include <wtf/PassRefPtr.h> -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> +#include <wtf/text/StringHash.h> namespace WebCore { -class String; - extern const int SQLAuthAllow; extern const int SQLAuthIgnore; extern const int SQLAuthDeny; class DatabaseAuthorizer : public ThreadSafeShared<DatabaseAuthorizer> { public: - static PassRefPtr<DatabaseAuthorizer> create() { return adoptRef(new DatabaseAuthorizer); } + static PassRefPtr<DatabaseAuthorizer> create(const String& databaseInfoTableName); int createTable(const String& tableName); int createTempTable(const String& tableName); @@ -90,19 +89,25 @@ public: void setReadOnly(); void reset(); + void resetDeletes(); bool lastActionWasInsert() const { return m_lastActionWasInsert; } bool lastActionChangedDatabase() const { return m_lastActionChangedDatabase; } + bool hadDeletes() const { return m_hadDeletes; } private: - DatabaseAuthorizer(); + DatabaseAuthorizer(const String& databaseInfoTableName); void addWhitelistedFunctions(); - int denyBasedOnTableName(const String&); + int denyBasedOnTableName(const String&) const; + int updateDeletesBasedOnTableName(const String&); bool m_securityEnabled : 1; bool m_lastActionWasInsert : 1; bool m_lastActionChangedDatabase : 1; bool m_readOnly : 1; + bool m_hadDeletes : 1; + + const String m_databaseInfoTableName; HashSet<String, CaseFoldingHash> m_whitelistedFunctions; }; diff --git a/WebCore/storage/DatabaseCallback.h b/WebCore/storage/DatabaseCallback.h new file mode 100644 index 0000000..8ad56ed --- /dev/null +++ b/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/WebCore/storage/DatabaseCallback.idl b/WebCore/storage/DatabaseCallback.idl new file mode 100644 index 0000000..c218680 --- /dev/null +++ b/WebCore/storage/DatabaseCallback.idl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] DatabaseCallback { + boolean handleEvent(in Database database); + boolean handleEvent(in DatabaseSync database); + }; +} diff --git a/WebCore/storage/DatabaseDetails.h b/WebCore/storage/DatabaseDetails.h index 9b0f506..ceebd35 100644 --- a/WebCore/storage/DatabaseDetails.h +++ b/WebCore/storage/DatabaseDetails.h @@ -41,6 +41,9 @@ public: : m_expectedUsage(0) , m_currentUsage(0) { +#ifndef NDEBUG + m_thread = currentThread(); +#endif } DatabaseDetails(const String& databaseName, const String& displayName, unsigned long long expectedUsage, unsigned long long currentUsage) @@ -49,19 +52,27 @@ public: , m_expectedUsage(expectedUsage) , m_currentUsage(currentUsage) { +#ifndef NDEBUG + m_thread = currentThread(); +#endif } const String& name() const { return m_name; } const String& displayName() const { return m_displayName; } unsigned long long expectedUsage() const { return m_expectedUsage; } unsigned long long currentUsage() const { return m_currentUsage; } +#ifndef NDEBUG + ThreadIdentifier thread() const { return m_thread; } +#endif private: String m_name; String m_displayName; unsigned long long m_expectedUsage; unsigned long long m_currentUsage; - +#ifndef NDEBUG + ThreadIdentifier m_thread; +#endif }; } // namespace WebCore diff --git a/WebCore/storage/DatabaseSync.cpp b/WebCore/storage/DatabaseSync.cpp new file mode 100644 index 0000000..9c654a1 --- /dev/null +++ b/WebCore/storage/DatabaseSync.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DatabaseSync.h" + +#if ENABLE(DATABASE) +#include "DatabaseCallback.h" +#include "DatabaseTracker.h" +#include "Logging.h" +#include "SQLException.h" +#include "SQLTransactionSync.h" +#include "SQLTransactionSyncCallback.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +PassRefPtr<DatabaseSync> DatabaseSync::openDatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, + unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec) +{ + ASSERT(context->isContextThread()); + + if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) { + LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data()); + return 0; + } + + RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(context, name, expectedVersion, displayName, estimatedSize)); + + if (!database->performOpenAndVerify(!creationCallback, ec)) { + LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data()); + DatabaseTracker::tracker().removeOpenDatabase(database.get()); + return 0; + } + + DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize); + + if (database->isNew() && creationCallback.get()) { + database->m_expectedVersion = ""; + LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get()); + creationCallback->handleEvent(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/WebCore/storage/DatabaseSync.h b/WebCore/storage/DatabaseSync.h new file mode 100644 index 0000000..6563b23 --- /dev/null +++ b/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/WebCore/storage/DatabaseSync.idl b/WebCore/storage/DatabaseSync.idl new file mode 100644 index 0000000..0064991 --- /dev/null +++ b/WebCore/storage/DatabaseSync.idl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=DATABASE, + OmitConstructor, + NoStaticTables + ] DatabaseSync { + readonly attribute DOMString version; + [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/WebCore/storage/DatabaseTask.cpp b/WebCore/storage/DatabaseTask.cpp index 702c96b..343ae1e 100644 --- a/WebCore/storage/DatabaseTask.cpp +++ b/WebCore/storage/DatabaseTask.cpp @@ -37,6 +37,9 @@ namespace WebCore { DatabaseTaskSynchronizer::DatabaseTaskSynchronizer() : m_taskCompleted(false) +#ifndef NDEBUG + , m_hasCheckedForTermination(false) +#endif { } @@ -67,6 +70,7 @@ DatabaseTask::DatabaseTask(Database* database, DatabaseTaskSynchronizer* synchro DatabaseTask::~DatabaseTask() { + ASSERT(m_complete || !m_synchronizer); } void DatabaseTask::performTask() @@ -78,30 +82,34 @@ void DatabaseTask::performTask() m_database->resetAuthorizer(); doPerformTask(); - m_database->performPolicyChecks(); 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. -DatabaseOpenTask::DatabaseOpenTask(Database* database, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success) +Database::DatabaseOpenTask::DatabaseOpenTask(Database* database, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success) : DatabaseTask(database, synchronizer) + , m_setVersionInNewDatabase(setVersionInNewDatabase) , m_code(code) , m_success(success) { ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous. } -void DatabaseOpenTask::doPerformTask() +void Database::DatabaseOpenTask::doPerformTask() { - m_success = database()->performOpenAndVerify(m_code); + m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_code); } #ifndef NDEBUG -const char* DatabaseOpenTask::debugTaskName() const +const char* Database::DatabaseOpenTask::debugTaskName() const { return "DatabaseOpenTask"; } @@ -110,18 +118,18 @@ const char* DatabaseOpenTask::debugTaskName() const // *** DatabaseCloseTask *** // Closes the database. -DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer) +Database::DatabaseCloseTask::DatabaseCloseTask(Database* database, DatabaseTaskSynchronizer* synchronizer) : DatabaseTask(database, synchronizer) { } -void DatabaseCloseTask::doPerformTask() +void Database::DatabaseCloseTask::doPerformTask() { database()->close(); } #ifndef NDEBUG -const char* DatabaseCloseTask::debugTaskName() const +const char* Database::DatabaseCloseTask::debugTaskName() const { return "DatabaseCloseTask"; } @@ -130,27 +138,20 @@ const char* DatabaseCloseTask::debugTaskName() const // *** DatabaseTransactionTask *** // Starts a transaction that will report its results via a callback. -DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction) +Database::DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction) : DatabaseTask(transaction->database(), 0) , m_transaction(transaction) { } -DatabaseTransactionTask::~DatabaseTransactionTask() -{ -} - -void DatabaseTransactionTask::doPerformTask() +void Database::DatabaseTransactionTask::doPerformTask() { - if (m_transaction->performNextStep()) { - // The transaction is complete, we can move on to the next one. - MutexLocker locker(m_transaction->database()->m_transactionInProgressMutex); - m_transaction->database()->scheduleTransaction(); - } + if (m_transaction->performNextStep()) + m_transaction->database()->inProgressTransactionCompleted(); } #ifndef NDEBUG -const char* DatabaseTransactionTask::debugTaskName() const +const char* Database::DatabaseTransactionTask::debugTaskName() const { return "DatabaseTransactionTask"; } @@ -159,20 +160,20 @@ const char* DatabaseTransactionTask::debugTaskName() const // *** DatabaseTableNamesTask *** // Retrieves a list of all tables in the database - for WebInspector support. -DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names) +Database::DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names) : DatabaseTask(database, synchronizer) , m_tableNames(names) { ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous. } -void DatabaseTableNamesTask::doPerformTask() +void Database::DatabaseTableNamesTask::doPerformTask() { m_tableNames = database()->performGetTableNames(); } #ifndef NDEBUG -const char* DatabaseTableNamesTask::debugTaskName() const +const char* Database::DatabaseTableNamesTask::debugTaskName() const { return "DatabaseTableNamesTask"; } diff --git a/WebCore/storage/DatabaseTask.h b/WebCore/storage/DatabaseTask.h index 998e373..b61e465 100644 --- a/WebCore/storage/DatabaseTask.h +++ b/WebCore/storage/DatabaseTask.h @@ -29,8 +29,10 @@ #define DatabaseTask_h #if ENABLE(DATABASE) +#include "Database.h" #include "ExceptionCode.h" #include "PlatformString.h" +#include "SQLTransaction.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> @@ -39,14 +41,6 @@ namespace WebCore { -class Database; -class DatabaseTask; -class DatabaseThread; -class SQLValue; -class SQLCallback; -class SQLTransaction; -class VersionChangeCallback; - // Can be used to wait until DatabaseTask is completed. // Has to be passed into DatabaseTask::create to be associated with the task. class DatabaseTaskSynchronizer : public Noncopyable { @@ -58,21 +52,32 @@ public: // Called by the task. void taskCompleted(); -private: +#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 { - friend class Database; 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*); @@ -84,35 +89,36 @@ private: DatabaseTaskSynchronizer* m_synchronizer; #ifndef NDEBUG - virtual const char* debugTaskName() const = 0; - bool m_complete; + virtual const char* debugTaskName() const = 0; + bool m_complete; #endif }; -class DatabaseOpenTask : public DatabaseTask { +class Database::DatabaseOpenTask : public DatabaseTask { public: - static PassOwnPtr<DatabaseOpenTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success) + static PassOwnPtr<DatabaseOpenTask> create(Database* db, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success) { - return new DatabaseOpenTask(db, synchronizer, code, success); + return adoptPtr(new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success)); } private: - DatabaseOpenTask(Database*, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success); + DatabaseOpenTask(Database*, bool setVersionInNewDatabase, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success); virtual void doPerformTask(); #ifndef NDEBUG virtual const char* debugTaskName() const; #endif + bool m_setVersionInNewDatabase; ExceptionCode& m_code; bool& m_success; }; -class DatabaseCloseTask : public DatabaseTask { +class Database::DatabaseCloseTask : public DatabaseTask { public: static PassOwnPtr<DatabaseCloseTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer) - { - return new DatabaseCloseTask(db, synchronizer); + { + return adoptPtr(new DatabaseCloseTask(db, synchronizer)); } private: @@ -124,17 +130,16 @@ private: #endif }; -class DatabaseTransactionTask : public DatabaseTask { +class Database::DatabaseTransactionTask : public DatabaseTask { public: // Transaction task is never synchronous, so no 'synchronizer' parameter. static PassOwnPtr<DatabaseTransactionTask> create(PassRefPtr<SQLTransaction> transaction) { - return new DatabaseTransactionTask(transaction); + return adoptPtr(new DatabaseTransactionTask(transaction)); } SQLTransaction* transaction() const { return m_transaction.get(); } - virtual ~DatabaseTransactionTask(); private: DatabaseTransactionTask(PassRefPtr<SQLTransaction>); @@ -146,11 +151,11 @@ private: RefPtr<SQLTransaction> m_transaction; }; -class DatabaseTableNamesTask : public DatabaseTask { +class Database::DatabaseTableNamesTask : public DatabaseTask { public: static PassOwnPtr<DatabaseTableNamesTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names) { - return new DatabaseTableNamesTask(db, synchronizer, names); + return adoptPtr(new DatabaseTableNamesTask(db, synchronizer, names)); } private: diff --git a/WebCore/storage/DatabaseThread.cpp b/WebCore/storage/DatabaseThread.cpp index ec4c6d1..3b790ee 100644 --- a/WebCore/storage/DatabaseThread.cpp +++ b/WebCore/storage/DatabaseThread.cpp @@ -37,13 +37,14 @@ #include "Logging.h" #include "SQLTransactionClient.h" #include "SQLTransactionCoordinator.h" +#include <wtf/UnusedParam.h> namespace WebCore { DatabaseThread::DatabaseThread() : m_threadID(0) - , m_transactionClient(new SQLTransactionClient()) - , m_transactionCoordinator(new SQLTransactionCoordinator()) + , m_transactionClient(adoptPtr(new SQLTransactionClient())) + , m_transactionCoordinator(adoptPtr(new SQLTransactionCoordinator())) , m_cleanupSync(0) { m_selfRef = this; @@ -75,8 +76,15 @@ void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync) m_queue.kill(); } -bool DatabaseThread::terminationRequested() const +bool DatabaseThread::terminationRequested(DatabaseTaskSynchronizer* taskSynchronizer) const { +#ifndef NDEBUG + if (taskSynchronizer) + taskSynchronizer->setHasCheckedForTermination(); +#else + UNUSED_PARAM(taskSynchronizer); +#endif + return m_queue.killed(); } @@ -113,14 +121,14 @@ void* DatabaseThread::databaseThread() openSetCopy.swap(m_openDatabaseSet); DatabaseSet::iterator end = openSetCopy.end(); for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it) - (*it)->close(); + (*it)->close(); } // Detach the thread so its resources are no longer of any concern to anyone else detachThread(m_threadID); DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync; - + // Clear the self refptr, possibly resulting in deletion m_selfRef = 0; @@ -148,11 +156,13 @@ void DatabaseThread::recordDatabaseClosed(Database* 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); } diff --git a/WebCore/storage/DatabaseThread.h b/WebCore/storage/DatabaseThread.h index 3702619..c81e376 100644 --- a/WebCore/storage/DatabaseThread.h +++ b/WebCore/storage/DatabaseThread.h @@ -55,7 +55,7 @@ public: bool start(); void requestTermination(DatabaseTaskSynchronizer* cleanupSync); - bool terminationRequested() const; + 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. diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp index 76492c9..1a13612 100644 --- a/WebCore/storage/DatabaseTracker.cpp +++ b/WebCore/storage/DatabaseTracker.cpp @@ -31,9 +31,9 @@ #if ENABLE(DATABASE) +#include "AbstractDatabase.h" #include "Chrome.h" #include "ChromeClient.h" -#include "Database.h" #include "DatabaseThread.h" #include "DatabaseTrackerClient.h" #include "Logging.h" @@ -49,53 +49,64 @@ using namespace std; +static WebCore::OriginQuotaManager& originQuotaManager() +{ + DEFINE_STATIC_LOCAL(WebCore::OriginQuotaManager, quotaManager, ()); + return quotaManager; +} + namespace WebCore { -OriginQuotaManager& DatabaseTracker::originQuotaManager() +static DatabaseTracker* staticTracker = 0; + +void DatabaseTracker::initializeTracker(const String& databasePath) { - populateOrigins(); - ASSERT(m_quotaManager); - return *m_quotaManager; + ASSERT(!staticTracker); + if (staticTracker) + return; + + staticTracker = new DatabaseTracker(databasePath); } DatabaseTracker& DatabaseTracker::tracker() { - DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ()); - return tracker; + if (!staticTracker) + staticTracker = new DatabaseTracker(""); + + return *staticTracker; } -DatabaseTracker::DatabaseTracker() +DatabaseTracker::DatabaseTracker(const String& databasePath) : m_client(0) - , m_proposedDatabase(0) -#ifndef NDEBUG - , m_thread(currentThread()) -#endif { + setDatabaseDirectoryPath(databasePath); + SQLiteFileSystem::registerSQLiteVFS(); + + MutexLocker lockDatabase(m_databaseGuard); + populateOrigins(); } void DatabaseTracker::setDatabaseDirectoryPath(const String& path) { - ASSERT(currentThread() == m_thread); + MutexLocker lockDatabase(m_databaseGuard); ASSERT(!m_database.isOpen()); - m_databaseDirectoryPath = path; + m_databaseDirectoryPath = path.threadsafeCopy(); } -const String& DatabaseTracker::databaseDirectoryPath() const +String DatabaseTracker::databaseDirectoryPath() const { - ASSERT(currentThread() == m_thread); - return m_databaseDirectoryPath; + return m_databaseDirectoryPath.threadsafeCopy(); } String DatabaseTracker::trackerDatabasePath() const { - ASSERT(currentThread() == m_thread); return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, "Databases.db"); } void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist) { - ASSERT(currentThread() == m_thread); + ASSERT(!m_databaseGuard.tryLock()); if (m_database.isOpen()) return; @@ -106,67 +117,94 @@ void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist) if (!m_database.open(databasePath)) { // FIXME: What do do here? + LOG_ERROR("Failed to open databasePath %s.", databasePath.ascii().data()); return; } + m_database.disableThreadingChecks(); if (!m_database.tableExists("Origins")) { if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) { // FIXME: and here + LOG_ERROR("Failed to create Origins table"); } } if (!m_database.tableExists("Databases")) { if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) { // FIXME: and here + LOG_ERROR("Failed to create Databases table"); } } } bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize) { - ASSERT(currentThread() == m_thread); + SecurityOrigin* origin = context->securityOrigin(); + ProposedDatabase details; - // Populate the origins before we establish a database; this guarantees that quotaForOrigin - // can run on the database thread later. - populateOrigins(); + unsigned long long requirement; + { + MutexLocker lockDatabase(m_databaseGuard); + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); - SecurityOrigin* origin = context->securityOrigin(); + if (!canCreateDatabase(origin, name)) + return false; - // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker - // by fetching it's current usage now - unsigned long long usage = usageForOrigin(origin); + recordCreatingDatabase(origin, name); - // If a database already exists, ignore the passed-in estimated size and say it's OK. - if (hasEntryForDatabase(origin, name)) - return true; + // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker + // by fetching its current usage now. + unsigned long long usage = usageForOriginNoLock(origin); - // If the database will fit, allow its creation. - unsigned long long requirement = usage + max(1UL, estimatedSize); - if (requirement < usage) - return false; // If the estimated size is so big it causes an overflow, don't allow creation. - if (requirement <= quotaForOrigin(origin)) - return true; + // If a database already exists, ignore the passed-in estimated size and say it's OK. + if (hasEntryForDatabase(origin, name)) + return true; - // Give the chrome client a chance to increase the quota. - // Temporarily make the details of the proposed database available, so the client can get at them. - pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0)); - m_proposedDatabase = &details; + // If the database will fit, allow its creation. + requirement = usage + max(1UL, estimatedSize); + if (requirement < usage) { + doneCreatingDatabase(origin, name); + return false; // If the estimated size is so big it causes an overflow, don't allow creation. + } + if (requirement <= quotaForOriginNoLock(origin)) + return true; + + // Give the chrome client a chance to increase the quota. + // Temporarily make the details of the proposed database available, so the client can get at them. + // FIXME: We should really just pass the details into this call, rather than using m_proposedDatabases. + details = ProposedDatabase(origin->threadsafeCopy(), DatabaseDetails(name.threadsafeCopy(), displayName.threadsafeCopy(), estimatedSize, 0)); + m_proposedDatabases.add(&details); + } + // Drop all locks before calling out; we don't know what they'll do. context->databaseExceededQuota(name); - m_proposedDatabase = 0; + + MutexLocker lockDatabase(m_databaseGuard); + + m_proposedDatabases.remove(&details); // If the database will fit now, allow its creation. - return requirement <= quotaForOrigin(origin); + if (requirement <= quotaForOriginNoLock(origin)) + return true; + + doneCreatingDatabase(origin, name); + + return false; } -bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin) +bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin) { - ASSERT(currentThread() == m_thread); - populateOrigins(); - MutexLocker lockQuotaMap(m_quotaMapGuard); + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(m_quotaMap); return m_quotaMap->contains(origin); } +bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin) +{ + MutexLocker lockDatabase(m_databaseGuard); + return hasEntryForOriginNoLock(origin); +} + bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& databaseIdentifier) { - ASSERT(currentThread() == m_thread); + ASSERT(!m_databaseGuard.tryLock()); openTrackerDatabase(false); if (!m_database.isOpen()) return false; @@ -181,28 +219,64 @@ bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& return statement.step() == SQLResultRow; } -unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database) +unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database) { - ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID()); // The maximum size for a database is the full quota for its origin, minus the current usage within the origin, // plus the current usage of the given database - Locker<OriginQuotaManager> locker(originQuotaManager()); + MutexLocker lockDatabase(m_databaseGuard); + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); SecurityOrigin* origin = database->securityOrigin(); - return quotaForOrigin(origin) - originQuotaManager().diskUsage(origin) + SQLiteFileSystem::getDatabaseFileSize(database->fileName()); + return quotaForOriginNoLock(origin) - originQuotaManager().diskUsage(origin) + SQLiteFileSystem::getDatabaseFileSize(database->fileName()); +} + +void DatabaseTracker::databaseChanged(AbstractDatabase* database) +{ + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + originQuotaManager().markDatabase(database); +} + +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 { - ASSERT(currentThread() == m_thread); - return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath, origin->databaseIdentifier()); + return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.threadsafeCopy(), origin->databaseIdentifier()); } -String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists) +String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const String& name, bool createIfNotExists) { - ASSERT(currentThread() == m_thread); + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(!originQuotaManager().tryLock()); - if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name) - return String(); + for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter) + if ((*iter)->second.name() == name && (*iter)->first->equal(origin)) + return String(); String originIdentifier = origin->databaseIdentifier(); String originPath = this->originPath(origin); @@ -212,7 +286,6 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String return String(); // See if we have a path for this database yet - openTrackerDatabase(false); if (!m_database.isOpen()) return String(); SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;"); @@ -231,36 +304,39 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String return String(); if (result != SQLResultDone) { - LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data()); + LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.ascii().data(), name.ascii().data()); return String(); } statement.finalize(); - String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, origin->databaseIdentifier(), &m_database); + String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, originIdentifier, &m_database); if (!addDatabase(origin, name, fileName)) return String(); // If this origin's quota is being tracked (open handle to a database in this origin), add this new database // to the quota manager now String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, fileName); - { - Locker<OriginQuotaManager> locker(originQuotaManager()); - if (originQuotaManager().tracksOrigin(origin)) - originQuotaManager().addDatabase(origin, name, fullFilePath); - } + if (originQuotaManager().tracksOrigin(origin)) + originQuotaManager().addDatabase(origin, name, fullFilePath); return fullFilePath; } +String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists) +{ + MutexLocker lockDatabase(m_databaseGuard); + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + + return fullPathForDatabaseNoLock(origin, name, createIfNotExists).threadsafeCopy(); +} + void DatabaseTracker::populateOrigins() { + ASSERT(!m_databaseGuard.tryLock()); if (m_quotaMap) return; - ASSERT(currentThread() == m_thread); - - m_quotaMap.set(new QuotaMap); - m_quotaManager.set(new OriginQuotaManager); + m_quotaMap = adoptPtr(new QuotaMap); openTrackerDatabase(false); if (!m_database.isOpen()) @@ -268,30 +344,31 @@ void DatabaseTracker::populateOrigins() SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Failed to prepare statement."); return; + } int result; while ((result = statement.step()) == SQLResultRow) { RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0)); - m_quotaMap->set(origin.get(), statement.getColumnInt64(1)); + m_quotaMap->set(origin.get()->threadsafeCopy(), statement.getColumnInt64(1)); } if (result != SQLResultDone) - LOG_ERROR("Failed to read in all origins from the database"); + LOG_ERROR("Failed to read in all origins from the database."); } void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result) { - ASSERT(currentThread() == m_thread); - populateOrigins(); - MutexLocker lockQuotaMap(m_quotaMapGuard); + MutexLocker lockDatabase(m_databaseGuard); + ASSERT(m_quotaMap); copyKeysToVector(*m_quotaMap, result); } -bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector) +bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector) { - ASSERT(currentThread() == m_thread); + ASSERT(!m_databaseGuard.tryLock()); openTrackerDatabase(false); if (!m_database.isOpen()) return false; @@ -315,44 +392,67 @@ bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri return true; } -DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin) +bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector) { - ASSERT(currentThread() == m_thread); + Vector<String> temp; + { + MutexLocker lockDatabase(m_databaseGuard); + if (!databaseNamesForOriginNoLock(origin, temp)) + return false; + } - if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name) - return m_proposedDatabase->second; + for (Vector<String>::iterator iter = temp.begin(); iter != temp.end(); ++iter) + resultVector.append(iter->threadsafeCopy()); + return true; +} +DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin) +{ String originIdentifier = origin->databaseIdentifier(); + String displayName; + int64_t expectedUsage; - openTrackerDatabase(false); - if (!m_database.isOpen()) - return DatabaseDetails(); - SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?"); - if (statement.prepare() != SQLResultOk) - return DatabaseDetails(); + { + MutexLocker lockDatabase(m_databaseGuard); - statement.bindText(1, originIdentifier); - statement.bindText(2, name); + for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin(); iter != m_proposedDatabases.end(); ++iter) + if ((*iter)->second.name() == name && (*iter)->first->equal(origin)) { + ASSERT((*iter)->second.thread() == currentThread()); + return (*iter)->second; + } - int result = statement.step(); - if (result == SQLResultDone) - return DatabaseDetails(); + openTrackerDatabase(false); + if (!m_database.isOpen()) + return DatabaseDetails(); + SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?"); + if (statement.prepare() != SQLResultOk) + return DatabaseDetails(); + + statement.bindText(1, originIdentifier); + statement.bindText(2, name); + + int result = statement.step(); + if (result == SQLResultDone) + return DatabaseDetails(); - if (result != SQLResultRow) { - LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data()); - return DatabaseDetails(); + if (result != SQLResultRow) { + LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data()); + return DatabaseDetails(); + } + displayName = statement.getColumnText(0); + expectedUsage = statement.getColumnInt64(1); } - return DatabaseDetails(name, statement.getColumnText(0), statement.getColumnInt64(1), usageForDatabase(name, origin)); + return DatabaseDetails(name, displayName, expectedUsage, usageForDatabase(name, origin)); } void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize) { - ASSERT(currentThread() == m_thread); - String originIdentifier = origin->databaseIdentifier(); int64_t guid = 0; + MutexLocker lockDatabase(m_databaseGuard); + openTrackerDatabase(true); if (!m_database.isOpen()) return; @@ -400,7 +500,6 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n unsigned long long DatabaseTracker::usageForDatabase(const String& name, SecurityOrigin* origin) { - ASSERT(currentThread() == m_thread); String path = fullPathForDatabase(origin, name, false); if (path.isEmpty()) return 0; @@ -408,77 +507,93 @@ unsigned long long DatabaseTracker::usageForDatabase(const String& name, Securit return SQLiteFileSystem::getDatabaseFileSize(path); } -void DatabaseTracker::addOpenDatabase(Database* database) +void DatabaseTracker::addOpenDatabase(AbstractDatabase* database) { if (!database) return; - MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); + { + MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); - if (!m_openDatabaseMap) - m_openDatabaseMap.set(new DatabaseOriginMap); + if (!m_openDatabaseMap) + m_openDatabaseMap = adoptPtr(new DatabaseOriginMap); - String name(database->stringIdentifier()); - DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); - if (!nameMap) { - nameMap = new DatabaseNameMap; - m_openDatabaseMap->set(database->securityOrigin(), nameMap); - } + String name(database->stringIdentifier()); + DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); + if (!nameMap) { + nameMap = new DatabaseNameMap; + m_openDatabaseMap->set(database->securityOrigin()->threadsafeCopy(), nameMap); + } - DatabaseSet* databaseSet = nameMap->get(name); - if (!databaseSet) { - databaseSet = new DatabaseSet; - nameMap->set(name, databaseSet); - } + DatabaseSet* databaseSet = nameMap->get(name); + if (!databaseSet) { + databaseSet = new DatabaseSet; + nameMap->set(name.threadsafeCopy(), databaseSet); + } - databaseSet->add(database); + databaseSet->add(database); - LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database); + LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database); + + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + if (!originQuotaManager().tracksOrigin(database->securityOrigin())) { + originQuotaManager().trackOrigin(database->securityOrigin()); + originQuotaManager().addDatabase(database->securityOrigin(), database->stringIdentifier(), database->fileName()); + } + } + + MutexLocker lockDatabase(m_databaseGuard); + doneCreatingDatabase(database->securityOrigin(), database->stringIdentifier()); } -void DatabaseTracker::removeOpenDatabase(Database* database) +void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database) { if (!database) return; - MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); + { + MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); - if (!m_openDatabaseMap) { - ASSERT_NOT_REACHED(); - return; - } + if (!m_openDatabaseMap) { + ASSERT_NOT_REACHED(); + return; + } - String name(database->stringIdentifier()); - DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); - if (!nameMap) { - ASSERT_NOT_REACHED(); - return; - } + String name(database->stringIdentifier()); + DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); + if (!nameMap) { + ASSERT_NOT_REACHED(); + return; + } - DatabaseSet* databaseSet = nameMap->get(name); - if (!databaseSet) { - ASSERT_NOT_REACHED(); - return; - } + DatabaseSet* databaseSet = nameMap->get(name); + if (!databaseSet) { + ASSERT_NOT_REACHED(); + return; + } - databaseSet->remove(database); + databaseSet->remove(database); - LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database); + LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database); - if (!databaseSet->isEmpty()) - return; + if (!databaseSet->isEmpty()) + return; - nameMap->remove(name); - delete databaseSet; + nameMap->remove(name); + delete databaseSet; - if (!nameMap->isEmpty()) - return; + if (!nameMap->isEmpty()) + return; + + m_openDatabaseMap->remove(database->securityOrigin()); + delete nameMap; - m_openDatabaseMap->remove(database->securityOrigin()); - delete nameMap; + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + originQuotaManager().removeOrigin(database->securityOrigin()); + } } -void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases) +void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) @@ -496,10 +611,9 @@ void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam databases->add(*it); } -unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin) +unsigned long long DatabaseTracker::usageForOriginNoLock(SecurityOrigin* origin) { - ASSERT(currentThread() == m_thread); - Locker<OriginQuotaManager> locker(originQuotaManager()); + ASSERT(!originQuotaManager().tryLock()); // Use the OriginQuotaManager mechanism to calculate the usage if (originQuotaManager().tracksOrigin(origin)) @@ -509,79 +623,93 @@ unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin) originQuotaManager().trackOrigin(origin); Vector<String> names; - databaseNamesForOrigin(origin, names); + databaseNamesForOriginNoLock(origin, names); for (unsigned i = 0; i < names.size(); ++i) - originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(origin, names[i], false)); + originQuotaManager().addDatabase(origin, names[i], fullPathForDatabaseNoLock(origin, names[i], false)); if (!originQuotaManager().tracksOrigin(origin)) return 0; return originQuotaManager().diskUsage(origin); } -unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin) +unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin) { - ASSERT(currentThread() == m_thread || m_quotaMap); - populateOrigins(); - MutexLocker lockQuotaMap(m_quotaMapGuard); + MutexLocker lockDatabase(m_databaseGuard); + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + return usageForOriginNoLock(origin); +} + +unsigned long long DatabaseTracker::quotaForOriginNoLock(SecurityOrigin* origin) +{ + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(m_quotaMap); return m_quotaMap->get(origin); } +unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin) +{ + MutexLocker lockDatabase(m_databaseGuard); + return quotaForOriginNoLock(origin); +} + void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota) { - ASSERT(currentThread() == m_thread); - if (quotaForOrigin(origin) == quota) + MutexLocker lockDatabase(m_databaseGuard); + + if (quotaForOriginNoLock(origin) == quota) return; openTrackerDatabase(true); if (!m_database.isOpen()) return; - { - MutexLocker lockQuotaMap(m_quotaMapGuard); - - if (!m_quotaMap->contains(origin)) { - SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)"); - if (statement.prepare() != SQLResultOk) { - LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data()); - } else { - statement.bindText(1, origin->databaseIdentifier()); - statement.bindInt64(2, quota); - - if (statement.step() != SQLResultDone) - LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data()); - } + if (!m_quotaMap->contains(origin)) { + SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)"); + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data()); } else { - SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?"); - bool error = statement.prepare() != SQLResultOk; - if (!error) { - statement.bindInt64(1, quota); - statement.bindText(2, origin->databaseIdentifier()); - - error = !statement.executeCommand(); - } + statement.bindText(1, origin->databaseIdentifier()); + statement.bindInt64(2, quota); - if (error) - LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data()); + if (statement.step() != SQLResultDone) + LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data()); + } + } else { + SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?"); + bool error = statement.prepare() != SQLResultOk; + if (!error) { + statement.bindInt64(1, quota); + statement.bindText(2, origin->databaseIdentifier()); + + error = !statement.executeCommand(); } - // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk? - m_quotaMap->set(origin, quota); + if (error) +#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(currentThread() == m_thread); + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(m_quotaMap); openTrackerDatabase(true); if (!m_database.isOpen()) return false; // New database should never be added until the origin has been established - ASSERT(hasEntryForOrigin(origin)); + ASSERT(hasEntryForOriginNoLock(origin)); SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);"); @@ -605,8 +733,6 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co void DatabaseTracker::deleteAllDatabases() { - ASSERT(currentThread() == m_thread); - Vector<RefPtr<SecurityOrigin> > originsCopy; origins(originsCopy); @@ -614,19 +740,30 @@ void DatabaseTracker::deleteAllDatabases() deleteOrigin(originsCopy[i].get()); } -void DatabaseTracker::deleteOrigin(SecurityOrigin* origin) +// It is the caller's responsibility to make sure that nobody is trying to create, delete, open, or close databases in this origin while the deletion is +// taking place. +bool DatabaseTracker::deleteOrigin(SecurityOrigin* origin) { - ASSERT(currentThread() == m_thread); - openTrackerDatabase(false); - if (!m_database.isOpen()) - return; - Vector<String> databaseNames; - if (!databaseNamesForOrigin(origin, databaseNames)) { - LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data()); - return; + { + MutexLocker lockDatabase(m_databaseGuard); + openTrackerDatabase(false); + if (!m_database.isOpen()) + return false; + + if (!databaseNamesForOriginNoLock(origin, databaseNames)) { + LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data()); + return false; + } + if (!canDeleteOrigin(origin)) { + LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin->databaseIdentifier().ascii().data()); + ASSERT(false); + return false; + } + recordDeletingOrigin(origin); } + // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock. for (unsigned i = 0; i < databaseNames.size(); ++i) { if (!deleteDatabaseFile(origin, databaseNames[i])) { // Even if the file can't be deleted, we want to try and delete the rest, don't return early here. @@ -634,41 +771,45 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin) } } - SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?"); - if (statement.prepare() != SQLResultOk) { - LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); - return; - } + { + MutexLocker lockDatabase(m_databaseGuard); + doneDeletingOrigin(origin); - statement.bindText(1, origin->databaseIdentifier()); + SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?"); + if (statement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); + return false; + } - if (!statement.executeCommand()) { - LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); - return; - } + statement.bindText(1, origin->databaseIdentifier()); - SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?"); - if (originStatement.prepare() != SQLResultOk) { - LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data()); - return; - } + if (!statement.executeCommand()) { + LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); + return false; + } - originStatement.bindText(1, origin->databaseIdentifier()); + SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?"); + if (originStatement.prepare() != SQLResultOk) { + LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data()); + return false; + } - if (!originStatement.executeCommand()) { - LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); - return; - } + originStatement.bindText(1, origin->databaseIdentifier()); - SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin)); + if (!originStatement.executeCommand()) { + LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data()); + return false; + } - RefPtr<SecurityOrigin> originPossiblyLastReference = origin; - { - MutexLocker lockQuotaMap(m_quotaMapGuard); + SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin)); + + RefPtr<SecurityOrigin> originPossiblyLastReference = origin; m_quotaMap->remove(origin); - Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); - originQuotaManager().removeOrigin(origin); + { + Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); + originQuotaManager().removeOrigin(origin); + } // If we removed the last origin, do some additional deletion. if (m_quotaMap->isEmpty()) { @@ -677,31 +818,159 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin) SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath); } + + if (m_client) { + m_client->dispatchDidModifyOrigin(origin); + for (unsigned i = 0; i < databaseNames.size(); ++i) + m_client->dispatchDidModifyDatabase(origin, databaseNames[i]); + } } + return true; +} - if (m_client) { - m_client->dispatchDidModifyOrigin(origin); - for (unsigned i = 0; i < databaseNames.size(); ++i) - m_client->dispatchDidModifyDatabase(origin, databaseNames[i]); +bool DatabaseTracker::canCreateDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + // Can't create a database while someone else is deleting it; there's a risk of leaving untracked database debris on the disk. + return !deletingDatabase(origin, name) && !deletingOrigin(origin); +} + +void DatabaseTracker::recordCreatingDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + NameCountMap* nameMap = m_beingCreated.get(origin); + if (!nameMap) { + nameMap = new NameCountMap(); + m_beingCreated.set(origin->threadsafeCopy(), nameMap); } + long count = nameMap->get(name); + nameMap->set(name.threadsafeCopy(), count + 1); } -void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) +void DatabaseTracker::doneCreatingDatabase(SecurityOrigin *origin, const String& name) { - ASSERT(currentThread() == m_thread); - openTrackerDatabase(false); - if (!m_database.isOpen()) - return; + ASSERT(!m_databaseGuard.tryLock()); + NameCountMap* nameMap = m_beingCreated.get(origin); + if (nameMap) { + long count = nameMap->get(name); + ASSERT(count > 0); + if (count <= 1) { + nameMap->remove(name); + if (nameMap->isEmpty()) { + m_beingCreated.remove(origin); + delete nameMap; + } + } else + nameMap->set(name, count - 1); + } else + ASSERT(false); +} + +bool DatabaseTracker::creatingDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + NameCountMap* nameMap = m_beingCreated.get(origin); + return nameMap && nameMap->get(name); +} + +bool DatabaseTracker::canDeleteDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + return !creatingDatabase(origin, name) && !deletingDatabase(origin, name); +} + +void DatabaseTracker::recordDeletingDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(canDeleteDatabase(origin, name)); + NameSet* nameSet = m_beingDeleted.get(origin); + if (!nameSet) { + nameSet = new NameSet(); + m_beingDeleted.set(origin->threadsafeCopy(), nameSet); + } + ASSERT(!nameSet->contains(name)); + nameSet->add(name.threadsafeCopy()); +} +void DatabaseTracker::doneDeletingDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + NameSet* nameSet = m_beingDeleted.get(origin); + if (nameSet) { + ASSERT(nameSet->contains(name)); + nameSet->remove(name); + if (nameSet->isEmpty()) { + m_beingDeleted.remove(origin); + delete nameSet; + } + } else { + ASSERT(false); + } +} + +bool DatabaseTracker::deletingDatabase(SecurityOrigin *origin, const String& name) +{ + ASSERT(!m_databaseGuard.tryLock()); + NameSet* nameSet = m_beingDeleted.get(origin); + return nameSet && nameSet->contains(name); +} + +bool DatabaseTracker::canDeleteOrigin(SecurityOrigin *origin) +{ + ASSERT(!m_databaseGuard.tryLock()); + return !(deletingOrigin(origin) || m_beingCreated.get(origin)); +} + +bool DatabaseTracker::deletingOrigin(SecurityOrigin *origin) +{ + ASSERT(!m_databaseGuard.tryLock()); + return m_originsBeingDeleted.contains(origin); +} + +void DatabaseTracker::recordDeletingOrigin(SecurityOrigin *origin) +{ + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(!deletingOrigin(origin)); + m_originsBeingDeleted.add(origin->threadsafeCopy()); +} + +void DatabaseTracker::doneDeletingOrigin(SecurityOrigin *origin) +{ + ASSERT(!m_databaseGuard.tryLock()); + ASSERT(deletingOrigin(origin)); + m_originsBeingDeleted.remove(origin); +} + +bool DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) +{ + { + MutexLocker lockDatabase(m_databaseGuard); + openTrackerDatabase(false); + if (!m_database.isOpen()) + return false; + + if (!canDeleteDatabase(origin, name)) { + ASSERT(FALSE); + return false; + } + recordDeletingDatabase(origin, name); + } + + // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock. if (!deleteDatabaseFile(origin, name)) { LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data()); - return; + MutexLocker lockDatabase(m_databaseGuard); + doneDeletingDatabase(origin, name); + return false; } + MutexLocker lockDatabase(m_databaseGuard); + SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?"); if (statement.prepare() != SQLResultOk) { LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); - return; + doneDeletingDatabase(origin, name); + return false; } statement.bindText(1, origin->databaseIdentifier()); @@ -709,7 +978,8 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) if (!statement.executeCommand()) { LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); - return; + doneDeletingDatabase(origin, name); + return false; } { @@ -721,28 +991,38 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) m_client->dispatchDidModifyOrigin(origin); m_client->dispatchDidModifyDatabase(origin, name); } + doneDeletingDatabase(origin, name); + + return true; } +// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them. While this is in progress, the caller +// is responsible for making sure no new databases are opened in the file to be deleted. bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name) { - ASSERT(currentThread() == m_thread); String fullPath = fullPathForDatabase(origin, name, false); if (fullPath.isEmpty()) return true; - Vector<RefPtr<Database> > deletedDatabases; +#ifndef NDEBUG + { + MutexLocker lockDatabase(m_databaseGuard); + ASSERT(deletingDatabase(origin, name) || deletingOrigin(origin)); + } +#endif + + Vector<RefPtr<AbstractDatabase> > deletedDatabases; - // Make sure not to hold the m_openDatabaseMapGuard mutex when calling + // Make sure not to hold the any locks when calling // Database::markAsDeletedAndClose(), since that can cause a deadlock // during the synchronous DatabaseThread call it triggers. - { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (m_openDatabaseMap) { // There are some open databases, lets check if they are for this origin. DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); if (nameMap && nameMap->size()) { - // There are some open databases for this origin, lets check + // There are some open databases for this origin, let's check // if they are this database by name. DatabaseSet* databaseSet = nameMap->get(name); if (databaseSet && databaseSet->size()) { @@ -763,7 +1043,6 @@ bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& n void DatabaseTracker::setClient(DatabaseTrackerClient* client) { - ASSERT(currentThread() == m_thread); m_client = client; } @@ -773,7 +1052,7 @@ static Mutex& notificationMutex() return mutex; } -typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue; +typedef Vector<pair<RefPtr<SecurityOrigin>, String> > NotificationQueue; static NotificationQueue& notificationQueue() { @@ -785,7 +1064,7 @@ void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, cons { MutexLocker locker(notificationMutex()); - notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.crossThreadString())); + notificationQueue().append(pair<RefPtr<SecurityOrigin>, String>(origin->threadsafeCopy(), name.crossThreadString())); scheduleForNotification(); } @@ -820,7 +1099,7 @@ void DatabaseTracker::notifyDatabasesChanged(void*) return; for (unsigned i = 0; i < notifications.size(); ++i) - theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, notifications[i].second); + theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first.get(), notifications[i].second); } diff --git a/WebCore/storage/DatabaseTracker.h b/WebCore/storage/DatabaseTracker.h index 4640b18..7145e6b 100644 --- a/WebCore/storage/DatabaseTracker.h +++ b/WebCore/storage/DatabaseTracker.h @@ -32,9 +32,9 @@ #if ENABLE(DATABASE) #include "PlatformString.h" -#include "StringHash.h" #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/text/StringHash.h> #if !PLATFORM(CHROMIUM) #include "DatabaseDetails.h" @@ -44,7 +44,7 @@ namespace WebCore { -class Database; +class AbstractDatabase; class ScriptExecutionContext; class SecurityOrigin; @@ -52,32 +52,38 @@ struct SecurityOriginHash; #if !PLATFORM(CHROMIUM) class DatabaseTrackerClient; -class OriginQuotaManager; struct SecurityOriginTraits; #endif // !PLATFORM(CHROMIUM) class DatabaseTracker : public Noncopyable { public: + static void initializeTracker(const String& databasePath); static DatabaseTracker& tracker(); - // FIXME: Due to workers having multiple threads in a single process sharing - // a DatabaseTracker, this singleton will have to be synchronized or moved - // to TLS. + // This singleton will potentially be used from multiple worker threads and the page's context thread simultaneously. To keep this safe, it's + // currently using 4 locks. In order to avoid deadlock when taking multiple locks, you must take them in the correct order: + // m_databaseGuard before quotaManager if both locks are needed. + // m_openDatabaseMapGuard before quotaManager if both locks are needed. + // m_databaseGuard and m_openDatabaseMapGuard currently don't overlap. + // notificationMutex() is currently independent of the other locks. bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize); void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize); String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true); - void addOpenDatabase(Database*); - void removeOpenDatabase(Database*); - void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases); + void addOpenDatabase(AbstractDatabase*); + void removeOpenDatabase(AbstractDatabase*); + void getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases); - unsigned long long getMaxSizeForDatabase(const Database*); + unsigned long long getMaxSizeForDatabase(const AbstractDatabase*); + void databaseChanged(AbstractDatabase*); + + void interruptAllDatabasesForContext(const ScriptExecutionContext*); private: - DatabaseTracker(); + DatabaseTracker(const String& databasePath); - typedef HashSet<Database*> DatabaseSet; + typedef HashSet<AbstractDatabase*> DatabaseSet; typedef HashMap<String, DatabaseSet*> DatabaseNameMap; typedef HashMap<RefPtr<SecurityOrigin>, DatabaseNameMap*, SecurityOriginHash> DatabaseOriginMap; @@ -87,7 +93,7 @@ private: #if !PLATFORM(CHROMIUM) public: void setDatabaseDirectoryPath(const String&); - const String& databaseDirectoryPath() const; + String databaseDirectoryPath() const; void origins(Vector<RefPtr<SecurityOrigin> >& result); bool databaseNamesForOrigin(SecurityOrigin*, Vector<String>& result); @@ -100,20 +106,23 @@ public: void setQuota(SecurityOrigin*, unsigned long long); void deleteAllDatabases(); - void deleteOrigin(SecurityOrigin*); - void deleteDatabase(SecurityOrigin*, const String& name); + bool deleteOrigin(SecurityOrigin*); + bool deleteDatabase(SecurityOrigin*, const String& name); void setClient(DatabaseTrackerClient*); // From a secondary thread, must be thread safe with its data void scheduleNotifyDatabaseChanged(SecurityOrigin*, const String& name); - OriginQuotaManager& originQuotaManager(); - - bool hasEntryForOrigin(SecurityOrigin*); private: + bool hasEntryForOriginNoLock(SecurityOrigin* origin); + String fullPathForDatabaseNoLock(SecurityOrigin*, const String& name, bool createIfDoesNotExist); + bool databaseNamesForOriginNoLock(SecurityOrigin* origin, Vector<String>& resultVector); + unsigned long long usageForOriginNoLock(SecurityOrigin* origin); + unsigned long long quotaForOriginNoLock(SecurityOrigin* origin); + String trackerDatabasePath() const; void openTrackerDatabase(bool createIfDoesNotExist); @@ -126,23 +135,38 @@ private: bool deleteDatabaseFile(SecurityOrigin*, const String& name); + // This lock protects m_database, m_quotaMap, m_proposedDatabases, m_databaseDirectoryPath, m_originsBeingDeleted, m_beingCreated, and m_beingDeleted. + Mutex m_databaseGuard; SQLiteDatabase m_database; typedef HashMap<RefPtr<SecurityOrigin>, unsigned long long, SecurityOriginHash> QuotaMap; - Mutex m_quotaMapGuard; mutable OwnPtr<QuotaMap> m_quotaMap; - OwnPtr<OriginQuotaManager> m_quotaManager; - String m_databaseDirectoryPath; DatabaseTrackerClient* m_client; - std::pair<SecurityOrigin*, DatabaseDetails>* m_proposedDatabase; - -#ifndef NDEBUG - ThreadIdentifier m_thread; -#endif + typedef std::pair<RefPtr<SecurityOrigin>, DatabaseDetails> ProposedDatabase; + HashSet<ProposedDatabase*> m_proposedDatabases; + + typedef HashMap<String, long> NameCountMap; + typedef HashMap<RefPtr<SecurityOrigin>, NameCountMap*, SecurityOriginHash> CreateSet; + CreateSet m_beingCreated; + typedef HashSet<String> NameSet; + HashMap<RefPtr<SecurityOrigin>, NameSet*, SecurityOriginHash> m_beingDeleted; + HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash> m_originsBeingDeleted; + bool canCreateDatabase(SecurityOrigin *origin, const String& name); + void recordCreatingDatabase(SecurityOrigin *origin, const String& name); + void doneCreatingDatabase(SecurityOrigin *origin, const String& name); + bool creatingDatabase(SecurityOrigin *origin, const String& name); + bool canDeleteDatabase(SecurityOrigin *origin, const String& name); + void recordDeletingDatabase(SecurityOrigin *origin, const String& name); + void doneDeletingDatabase(SecurityOrigin *origin, const String& name); + bool deletingDatabase(SecurityOrigin *origin, const String& name); + bool canDeleteOrigin(SecurityOrigin *origin); + bool deletingOrigin(SecurityOrigin *origin); + void recordDeletingOrigin(SecurityOrigin *origin); + void doneDeletingOrigin(SecurityOrigin *origin); static void scheduleForNotification(); static void notifyDatabasesChanged(void*); diff --git a/WebCore/storage/DatabaseTrackerClient.h b/WebCore/storage/DatabaseTrackerClient.h index b43123c..2e0497f 100644 --- a/WebCore/storage/DatabaseTrackerClient.h +++ b/WebCore/storage/DatabaseTrackerClient.h @@ -30,10 +30,11 @@ #if ENABLE(DATABASE) +#include <wtf/Forward.h> + namespace WebCore { class SecurityOrigin; -class String; class DatabaseTrackerClient { public: diff --git a/WebCore/storage/DirectoryEntry.cpp b/WebCore/storage/DirectoryEntry.cpp new file mode 100644 index 0000000..60dcace --- /dev/null +++ b/WebCore/storage/DirectoryEntry.cpp @@ -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: + * + * * 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 "DirectoryEntry.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DirectoryReader.h" +#include "EntryCallback.h" +#include "ErrorCallback.h" + +namespace WebCore { + +DirectoryEntry::DirectoryEntry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath) + : Entry(fileSystem, fullPath) +{ +} + +PassRefPtr<DirectoryReader> DirectoryEntry::createReader() +{ + return DirectoryReader::create(m_fileSystem, m_fullPath); +} + +void DirectoryEntry::getFile(const String&, PassRefPtr<Flags>, PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +void DirectoryEntry::getDirectory(const String&, PassRefPtr<Flags>, PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/DirectoryEntry.h b/WebCore/storage/DirectoryEntry.h new file mode 100644 index 0000000..2ae4fb5 --- /dev/null +++ b/WebCore/storage/DirectoryEntry.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: + * + * * 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 DirectoryEntry_h +#define DirectoryEntry_h + +#if ENABLE(FILE_SYSTEM) + +#include "Entry.h" +#include "Flags.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class DirectoryReader; +class EntryCallback; +class ErrorCallback; + +class DirectoryEntry : public Entry { +public: + static PassRefPtr<DirectoryEntry> create(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath) + { + return adoptRef(new DirectoryEntry(fileSystem, fullPath)); + } + virtual bool isDirectory() const { return true; } + + PassRefPtr<DirectoryReader> createReader(); + void getFile(const String& path, PassRefPtr<Flags> options = 0, PassRefPtr<EntryCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + void getDirectory(const String& path, PassRefPtr<Flags> options = 0, PassRefPtr<EntryCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + +private: + DirectoryEntry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath); +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // DirectoryEntry_h diff --git a/WebCore/storage/DirectoryEntry.idl b/WebCore/storage/DirectoryEntry.idl new file mode 100644 index 0000000..ac30c7f --- /dev/null +++ b/WebCore/storage/DirectoryEntry.idl @@ -0,0 +1,41 @@ +/* + * 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=FILE_SYSTEM, + GenerateNativeConverter, + GenerateToJS + ] DirectoryEntry : Entry { + DirectoryReader createReader(); + void getFile(in DOMString path, in [Optional] Flags options, in [Optional, Callback] EntryCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + void getDirectory(in DOMString path, in [Optional] Flags options, in [Optional, Callback] EntryCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + }; +} diff --git a/WebCore/storage/DirectoryReader.cpp b/WebCore/storage/DirectoryReader.cpp new file mode 100644 index 0000000..0b30f70 --- /dev/null +++ b/WebCore/storage/DirectoryReader.cpp @@ -0,0 +1,56 @@ +/* + * 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 "DirectoryReader.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include "EntriesCallback.h" +#include "ErrorCallback.h" + +namespace WebCore { + +DirectoryReader::DirectoryReader(PassRefPtr<DOMFileSystem> fileSystem, const String& path) + : m_fileSystem(fileSystem) + , m_path(path) +{ +} + +void DirectoryReader::readEntries(PassRefPtr<EntriesCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/DirectoryReader.h b/WebCore/storage/DirectoryReader.h new file mode 100644 index 0000000..cf5da8f --- /dev/null +++ b/WebCore/storage/DirectoryReader.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: + * + * * 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 DirectoryReader_h +#define DirectoryReader_h + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class EntriesCallback; +class ErrorCallback; + +class DirectoryReader : public RefCounted<DirectoryReader> { +public: + static PassRefPtr<DirectoryReader> create(PassRefPtr<DOMFileSystem> fileSystem, const String& path) + { + return adoptRef(new DirectoryReader(fileSystem, path)); + } + + void readEntries(PassRefPtr<EntriesCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback = 0); + +private: + DirectoryReader(PassRefPtr<DOMFileSystem> fileSystem, const String& path); + + RefPtr<DOMFileSystem> m_fileSystem; + String m_path; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // DirectoryReader_h diff --git a/WebCore/storage/DirectoryReader.idl b/WebCore/storage/DirectoryReader.idl new file mode 100644 index 0000000..c3c7012 --- /dev/null +++ b/WebCore/storage/DirectoryReader.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: + * + * * 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=FILE_SYSTEM + ] DirectoryReader { + void readEntries(in [Callback] EntriesCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + }; +} diff --git a/WebCore/storage/EntriesCallback.h b/WebCore/storage/EntriesCallback.h new file mode 100644 index 0000000..9f812e9 --- /dev/null +++ b/WebCore/storage/EntriesCallback.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: + * + * * 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 EntriesCallback_h +#define EntriesCallback_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class EntryArray; + +class EntriesCallback : public RefCounted<EntriesCallback> { +public: + virtual ~EntriesCallback() { } + virtual bool handleEvent(EntryArray*) = 0; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // EntriesCallback_h diff --git a/WebCore/storage/EntriesCallback.idl b/WebCore/storage/EntriesCallback.idl new file mode 100644 index 0000000..73b374d --- /dev/null +++ b/WebCore/storage/EntriesCallback.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=FILE_SYSTEM, + Callback + ] EntriesCallback { + boolean handleEvent(in EntryArray entries); + }; +} diff --git a/WebCore/storage/Entry.cpp b/WebCore/storage/Entry.cpp new file mode 100644 index 0000000..6783291 --- /dev/null +++ b/WebCore/storage/Entry.cpp @@ -0,0 +1,93 @@ +/* + * 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 "Entry.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include "EntryCallback.h" +#include "ErrorCallback.h" +#include "MetadataCallback.h" +#include "VoidCallback.h" + +namespace WebCore { + +Entry::Entry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath) + : m_fileSystem(fileSystem) + , m_fullPath(fullPath) +{ + size_t index = fullPath.reverseFind("/"); + if (index != notFound) + m_name = fullPath.substring(index); + else + m_name = fullPath; +} + +void Entry::getMetadata(PassRefPtr<MetadataCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +void Entry::moveTo(PassRefPtr<Entry>, const String&, PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +void Entry::copyTo(PassRefPtr<Entry>, const String&, PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +void Entry::remove(PassRefPtr<VoidCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +void Entry::getParent(PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); +} + +String Entry::toURI(const String&) +{ + // FIXME: to be implemented. + ASSERT_NOT_REACHED(); + return String(); +} + +} // namespace WebCore + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/Entry.h b/WebCore/storage/Entry.h new file mode 100644 index 0000000..7bbb265 --- /dev/null +++ b/WebCore/storage/Entry.h @@ -0,0 +1,80 @@ +/* + * 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 Entry_h +#define Entry_h + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class EntryCallback; +class ErrorCallback; +class MetadataCallback; +class VoidCallback; + +class Entry : public RefCounted<Entry> { +public: + virtual ~Entry() { } + + virtual bool isFile() const { return false; } + virtual bool isDirectory() const { return false; } + + const String& fullPath() const { return m_fullPath; } + const String& name() const { return m_name; } + + DOMFileSystem* filesystem() const { return m_fileSystem.get(); } + + virtual void getMetadata(PassRefPtr<MetadataCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + + virtual void moveTo(PassRefPtr<Entry> parent, const String& name = String(), PassRefPtr<EntryCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + virtual void copyTo(PassRefPtr<Entry> parent, const String& name = String(), PassRefPtr<EntryCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + virtual void remove(PassRefPtr<VoidCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + virtual void getParent(PassRefPtr<EntryCallback> successCallback = 0, PassRefPtr<ErrorCallback> errorCallback = 0); + + virtual String toURI(const String& mimeType = String()); + +protected: + Entry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath); + + RefPtr<DOMFileSystem> m_fileSystem; + String m_fullPath; // virtual path + String m_name; +}; + +} // namespace WebCore + +#endif // ENABLE(FILE_SYSTEM) + +#endif // Entry_h diff --git a/WebCore/storage/Entry.idl b/WebCore/storage/Entry.idl new file mode 100644 index 0000000..7d4ffee --- /dev/null +++ b/WebCore/storage/Entry.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: + * + * * 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=FILE_SYSTEM + ] Entry { + readonly attribute boolean isFile; + readonly attribute boolean isDirectory; + readonly attribute DOMString name; + readonly attribute DOMString fullPath; + readonly attribute DOMFileSystem filesystem; + + void moveTo(in Entry parent, in [Optional] DOMString name, in [Optional, Callback] EntryCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + void copyTo(in Entry parent, in [Optional] DOMString name, in [Optional, Callback] EntryCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + void remove(in [Optional, Callback] VoidCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + void getParent(in [Optional, Callback] EntryCallback successCallback, in [Optional, Callback] ErrorCallback errorCallback); + DOMString toURI(in [Optional] DOMString mimeType); + }; +} diff --git a/WebCore/storage/EntryArray.cpp b/WebCore/storage/EntryArray.cpp new file mode 100644 index 0000000..6c4f74f --- /dev/null +++ b/WebCore/storage/EntryArray.cpp @@ -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. + */ + +#include "config.h" +#include "EntryArray.h" + +#if ENABLE(FILE_SYSTEM) + +namespace WebCore { + +EntryArray::EntryArray() +{ +} + +Entry* EntryArray::item(unsigned index) const +{ + if (index >= m_entries.size()) + return 0; + return m_entries[index].get(); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/EntryArray.h b/WebCore/storage/EntryArray.h new file mode 100644 index 0000000..e5957ab --- /dev/null +++ b/WebCore/storage/EntryArray.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * 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 EntryArray_h +#define EntryArray_h + +#if ENABLE(FILE_SYSTEM) + +#include "Entry.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class EntryArray : public RefCounted<EntryArray> { +public: + static PassRefPtr<EntryArray> create() + { + return adoptRef(new EntryArray()); + } + + unsigned length() const { return m_entries.size(); } + Entry* item(unsigned index) const; + void set(unsigned index, PassRefPtr<Entry> entry); + + bool isEmpty() const { return m_entries.isEmpty(); } + void clear() { m_entries.clear(); } + void append(PassRefPtr<Entry> entry) { m_entries.append(entry); } + +private: + EntryArray(); + + Vector<RefPtr<Entry> > m_entries; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // EntryArray_h diff --git a/WebCore/storage/EntryArray.idl b/WebCore/storage/EntryArray.idl new file mode 100644 index 0000000..e987ece --- /dev/null +++ b/WebCore/storage/EntryArray.idl @@ -0,0 +1,39 @@ +/* + * 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=FILE_SYSTEM, + HasIndexGetter, + ] EntryArray { + readonly attribute unsigned long length; + Entry item(in [IsIndex] unsigned long index); + }; +} diff --git a/WebCore/storage/EntryCallback.h b/WebCore/storage/EntryCallback.h new file mode 100644 index 0000000..9580eda --- /dev/null +++ b/WebCore/storage/EntryCallback.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: + * + * * 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 EntryCallback_h +#define EntryCallback_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Entry; + +class EntryCallback : public RefCounted<EntryCallback> { +public: + virtual ~EntryCallback() { } + virtual bool handleEvent(Entry*) = 0; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // EntryCallback_h diff --git a/WebCore/storage/EntryCallback.idl b/WebCore/storage/EntryCallback.idl new file mode 100644 index 0000000..bea3fd1 --- /dev/null +++ b/WebCore/storage/EntryCallback.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=FILE_SYSTEM, + Callback + ] EntryCallback { + boolean handleEvent(in Entry entry); + }; +} diff --git a/WebCore/storage/ErrorCallback.h b/WebCore/storage/ErrorCallback.h new file mode 100644 index 0000000..91143e8 --- /dev/null +++ b/WebCore/storage/ErrorCallback.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 ErrorCallback_h +#define ErrorCallback_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class FileError; +class ScriptExecutionContext; + +class ErrorCallback : public RefCounted<ErrorCallback> { +public: + virtual ~ErrorCallback() { } + virtual bool handleEvent(FileError*) = 0; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // ErrorCallback_h diff --git a/WebCore/storage/ErrorCallback.idl b/WebCore/storage/ErrorCallback.idl new file mode 100644 index 0000000..fc7fa85 --- /dev/null +++ b/WebCore/storage/ErrorCallback.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=FILE_SYSTEM, + Callback + ] ErrorCallback { + boolean handleEvent(in FileError error); + }; +} diff --git a/WebCore/storage/FileEntry.cpp b/WebCore/storage/FileEntry.cpp new file mode 100644 index 0000000..4bec01d --- /dev/null +++ b/WebCore/storage/FileEntry.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * 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 "FileEntry.h" + +#if ENABLE(FILE_SYSTEM) + +namespace WebCore { + +FileEntry::FileEntry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath) + : Entry(fileSystem, fullPath) +{ +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/FileEntry.h b/WebCore/storage/FileEntry.h new file mode 100644 index 0000000..b02b5c7 --- /dev/null +++ b/WebCore/storage/FileEntry.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: + * + * * 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 FileEntry_h +#define FileEntry_h + +#if ENABLE(FILE_SYSTEM) + +#include "Entry.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class DOMFileSystem; + +class FileEntry : public Entry { +public: + static PassRefPtr<FileEntry> create(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath) + { + return adoptRef(new FileEntry(fileSystem, fullPath)); + } + virtual bool isFile() const { return true; } + +private: + FileEntry(PassRefPtr<DOMFileSystem> fileSystem, const String& fullPath); +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // FileEntry_h diff --git a/WebCore/storage/FileEntry.idl b/WebCore/storage/FileEntry.idl new file mode 100644 index 0000000..af3b807 --- /dev/null +++ b/WebCore/storage/FileEntry.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=FILE_SYSTEM, + GenerateNativeConverter, + GenerateToJS + ] FileEntry : Entry { + }; +} diff --git a/WebCore/storage/FileSystemCallback.h b/WebCore/storage/FileSystemCallback.h new file mode 100644 index 0000000..63f8416 --- /dev/null +++ b/WebCore/storage/FileSystemCallback.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: + * + * * 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 FileSystemCallback_h +#define FileSystemCallback_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class DOMFileSystem; + +class FileSystemCallback : public RefCounted<FileSystemCallback> { +public: + virtual ~FileSystemCallback() { } + virtual bool handleEvent(DOMFileSystem*) = 0; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // FileSystemCallback_h diff --git a/WebCore/storage/FileSystemCallback.idl b/WebCore/storage/FileSystemCallback.idl new file mode 100644 index 0000000..cf686ff --- /dev/null +++ b/WebCore/storage/FileSystemCallback.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=FILE_SYSTEM, + Callback + ] FileSystemCallback { + boolean handleEvent(in DOMFileSystem fileSystem); + }; +} diff --git a/WebCore/storage/FileSystemCallbacks.cpp b/WebCore/storage/FileSystemCallbacks.cpp new file mode 100644 index 0000000..ec352dd --- /dev/null +++ b/WebCore/storage/FileSystemCallbacks.cpp @@ -0,0 +1,200 @@ +/* + * 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 "FileSystemCallbacks.h" + +#if ENABLE(FILE_SYSTEM) + +#include "DOMFileSystem.h" +#include "DirectoryEntry.h" +#include "EntriesCallback.h" +#include "EntryArray.h" +#include "EntryCallback.h" +#include "ErrorCallback.h" +#include "ExceptionCode.h" +#include "FileEntry.h" +#include "FileError.h" +#include "FileSystemCallback.h" +#include "Metadata.h" +#include "MetadataCallback.h" +#include "ScriptExecutionContext.h" +#include "VoidCallback.h" + +namespace WebCore { + +FileSystemCallbacksBase::FileSystemCallbacksBase(PassRefPtr<ErrorCallback> errorCallback) + : m_errorCallback(errorCallback) +{ +} + +FileSystemCallbacksBase::~FileSystemCallbacksBase() +{ +} + +void FileSystemCallbacksBase::didSucceed() +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didOpenFileSystem(const String&, const String&) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadMetadata(double) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadDirectoryChunkDone(bool) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didReadDirectoryEntry(const String&, bool) +{ + // Each subclass must implement an appropriate one. + ASSERT_NOT_REACHED(); +} + +void FileSystemCallbacksBase::didFail(ExceptionCode code) +{ + if (m_errorCallback) { + m_errorCallback->handleEvent(FileError::create(code).get()); + m_errorCallback.clear(); + } +} + +// EntryCallbacks ------------------------------------------------------------- + +EntryCallbacks::EntryCallbacks(PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, DOMFileSystem* fileSystem, const String& expectedPath, bool isDirectory) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) + , m_fileSystem(fileSystem) + , m_expectedPath(expectedPath) + , m_isDirectory(isDirectory) +{ +} + +void EntryCallbacks::didSucceed() +{ + if (m_successCallback) { + if (m_isDirectory) + m_successCallback->handleEvent(DirectoryEntry::create(m_fileSystem, m_expectedPath).get()); + else + m_successCallback->handleEvent(FileEntry::create(m_fileSystem, m_expectedPath).get()); + } + m_successCallback.clear(); +} + +// EntriesCallbacks ----------------------------------------------------------- + +EntriesCallbacks::EntriesCallbacks(PassRefPtr<EntriesCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, DOMFileSystem* fileSystem, const String& basePath) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) + , m_fileSystem(fileSystem) + , m_basePath(basePath) +{ +} + +void EntriesCallbacks::didReadDirectoryEntry(const String& name, bool isDirectory) +{ + if (isDirectory) + m_entries->append(DirectoryEntry::create(m_fileSystem, m_basePath + "/" + name)); + else + m_entries->append(FileEntry::create(m_fileSystem, m_basePath + "/" + name)); +} + +void EntriesCallbacks::didReadDirectoryChunkDone(bool hasMore) +{ + if (m_successCallback) { + m_successCallback->handleEvent(m_entries.get()); + m_entries->clear(); + if (!hasMore) { + // If there're no more entries, call back once more with an empty array. + m_successCallback->handleEvent(m_entries.get()); + m_successCallback.clear(); + } + } +} + +// FileSystemCallbacks -------------------------------------------------------- + +FileSystemCallbacks::FileSystemCallbacks(PassRefPtr<FileSystemCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void FileSystemCallbacks::didOpenFileSystem(const String& name, const String& rootPath) +{ + if (m_successCallback) + m_successCallback->handleEvent(DOMFileSystem::create(name, rootPath).get()); + m_successCallback.clear(); +} + +// MetadataCallbacks ---------------------------------------------------------- + +MetadataCallbacks::MetadataCallbacks(PassRefPtr<MetadataCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void MetadataCallbacks::didReadMetadata(double modificationTime) +{ + if (m_successCallback) + m_successCallback->handleEvent(Metadata::create(modificationTime).get()); + m_successCallback.clear(); +} + +// VoidCallbacks -------------------------------------------------------------- + +VoidCallbacks::VoidCallbacks(PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) + : FileSystemCallbacksBase(errorCallback) + , m_successCallback(successCallback) +{ +} + +void VoidCallbacks::didSucceed() +{ + if (m_successCallback) + m_successCallback->handleEvent(); + m_successCallback.clear(); +} + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) diff --git a/WebCore/storage/FileSystemCallbacks.h b/WebCore/storage/FileSystemCallbacks.h new file mode 100644 index 0000000..e0e78d3 --- /dev/null +++ b/WebCore/storage/FileSystemCallbacks.h @@ -0,0 +1,138 @@ +/* + * 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 FileSystemCallbacks_h +#define FileSystemCallbacks_h + +#if ENABLE(FILE_SYSTEM) + +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class DOMFileSystem; +class ErrorCallback; +class EntriesCallback; +class EntryArray; +class EntryCallback; +class FileSystemCallback; +class MetadataCallback; +class ScriptExecutionContext; +class VoidCallback; + +typedef int ExceptionCode; + +// A base class for FileSystem callbacks that bundles successCallback, errorCallback and some closure data for the callbacks. +class FileSystemCallbacksBase : public Noncopyable { +public: + virtual ~FileSystemCallbacksBase(); + + // For EntryCallbacks and VoidCallbacks. + virtual void didSucceed(); + + // For FileSystemCallbacks. + virtual void didOpenFileSystem(const String& name, const String& rootPath); + + // For MetadataCallbacks. + virtual void didReadMetadata(double modificationTime); + + // For EntriesCallbacks. didReadDirectoryEntry is called each time the API reads an entry, and didReadDirectoryDone is called when a chunk of entries have been read (i.e. good time to call back to the application). If hasMore is true there can be more chunks. + virtual void didReadDirectoryEntry(const String& name, bool isDirectory); + virtual void didReadDirectoryChunkDone(bool hasMore); + + // For ErrorCallback. + virtual void didFail(ExceptionCode code); + +protected: + FileSystemCallbacksBase(PassRefPtr<ErrorCallback> errorCallback); + RefPtr<ErrorCallback> m_errorCallback; +}; + +// Subclasses ---------------------------------------------------------------- + +class EntryCallbacks : public FileSystemCallbacksBase { +public: + EntryCallbacks(PassRefPtr<EntryCallback>, PassRefPtr<ErrorCallback>, DOMFileSystem*, const String& expectedPath, bool isDirectory); + virtual void didSucceed(); + +private: + RefPtr<EntryCallback> m_successCallback; + DOMFileSystem* m_fileSystem; + String m_expectedPath; + bool m_isDirectory; +}; + +class EntriesCallbacks : public FileSystemCallbacksBase { +public: + EntriesCallbacks(PassRefPtr<EntriesCallback>, PassRefPtr<ErrorCallback>, DOMFileSystem*, const String& basePath); + virtual void didReadDirectoryEntry(const String& name, bool isDirectory); + virtual void didReadDirectoryChunkDone(bool hasMore); + +private: + RefPtr<EntriesCallback> m_successCallback; + DOMFileSystem* m_fileSystem; + String m_basePath; + RefPtr<EntryArray> m_entries; +}; + +class FileSystemCallbacks : public FileSystemCallbacksBase { +public: + FileSystemCallbacks(PassRefPtr<FileSystemCallback>, PassRefPtr<ErrorCallback>); + virtual void didOpenFileSystem(const String& name, const String& rootPath); + +private: + RefPtr<FileSystemCallback> m_successCallback; +}; + +class MetadataCallbacks : public FileSystemCallbacksBase { +public: + MetadataCallbacks(PassRefPtr<MetadataCallback>, PassRefPtr<ErrorCallback>); + virtual void didReadMetadata(double modificationTime); + +private: + RefPtr<MetadataCallback> m_successCallback; +}; + +class VoidCallbacks : public FileSystemCallbacksBase { +public: + VoidCallbacks(PassRefPtr<VoidCallback>, PassRefPtr<ErrorCallback>); + virtual void didSucceed(); + +private: + RefPtr<VoidCallback> m_successCallback; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // FileSystemCallbacks_h diff --git a/WebCore/storage/Flags.h b/WebCore/storage/Flags.h new file mode 100644 index 0000000..ffe3403 --- /dev/null +++ b/WebCore/storage/Flags.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: + * + * * 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 Flags_h +#define Flags_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Flags : public RefCounted<Flags> { +public: + static PassRefPtr<Flags> create(bool create = false, bool exclusive = false) + { + return adoptRef(new Flags(create, exclusive)); + } + + bool isCreate() const { return m_create; } + void setCreate(bool create) { m_create = create; } + bool isExclusive() const { return m_exclusive; } + void setExclusive(bool exclusive) { m_exclusive = exclusive; } + +private: + Flags(bool create, bool exclusive) + : m_create(create) + , m_exclusive(exclusive) + { + } + bool m_create; + bool m_exclusive; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // Flags_h diff --git a/WebCore/storage/Flags.idl b/WebCore/storage/Flags.idl new file mode 100644 index 0000000..cfe73d2 --- /dev/null +++ b/WebCore/storage/Flags.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=FILE_SYSTEM + ] Flags { + attribute boolean CREATE; + attribute boolean EXCLUSIVE; + }; +} diff --git a/WebCore/storage/IDBAbortEvent.cpp b/WebCore/storage/IDBAbortEvent.cpp new file mode 100644 index 0000000..21760f8 --- /dev/null +++ b/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/WebCore/storage/IDBAbortEvent.h b/WebCore/storage/IDBAbortEvent.h new file mode 100644 index 0000000..bdc2202 --- /dev/null +++ b/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/WebCore/storage/IDBAny.cpp b/WebCore/storage/IDBAny.cpp new file mode 100644 index 0000000..93d2633 --- /dev/null +++ b/WebCore/storage/IDBAny.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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::create() +{ + return adoptRef(new IDBAny()); +} + +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<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<IDBFactory> IDBAny::idbFactory() +{ + ASSERT(m_type == IDBFactoryType); + return m_idbFactory; +} + +PassRefPtr<SerializedScriptValue> IDBAny::serializedScriptValue() +{ + ASSERT(m_type == SerializedScriptValueType); + return m_serializedScriptValue; +} + +void IDBAny::set() +{ + ASSERT(m_type == UndefinedType); + m_type = NullType; +} + +void IDBAny::set(PassRefPtr<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<IDBIndex> value) +{ + ASSERT(m_type == UndefinedType); + m_type = IDBDatabaseType; + m_idbIndex = value; +} + +void IDBAny::set(PassRefPtr<IDBKey> value) +{ + ASSERT(m_type == UndefinedType); + m_type = IDBKeyType; + m_idbKey = value; +} + +void IDBAny::set(PassRefPtr<IDBObjectStore> value) +{ + ASSERT(m_type == UndefinedType); + m_type = IDBObjectStoreType; + m_idbObjectStore = value; +} + +void IDBAny::set(PassRefPtr<IDBFactory> value) +{ + ASSERT(m_type == UndefinedType); + m_type = IDBFactoryType; + m_idbFactory = value; +} + +void IDBAny::set(PassRefPtr<SerializedScriptValue> value) +{ + ASSERT(m_type == UndefinedType); + m_type = SerializedScriptValueType; + m_serializedScriptValue = value; +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBAny.h b/WebCore/storage/IDBAny.h new file mode 100644 index 0000000..950660a --- /dev/null +++ b/WebCore/storage/IDBAny.h @@ -0,0 +1,108 @@ +/* + * 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 IDBIndex; +class IDBKey; +class IDBObjectStore; +class IDBFactory; +class SerializedScriptValue; + +class IDBAny : public RefCounted<IDBAny> { +public: + static PassRefPtr<IDBAny> create(); + template<typename T> + static PassRefPtr<IDBAny> create(T* idbObject) + { + RefPtr<IDBAny> any = IDBAny::create(); + any->set(idbObject); + return any.release(); + } + ~IDBAny(); + + enum Type { + UndefinedType = 0, + NullType, + IDBCursorType, + IDBDatabaseType, + IDBFactoryType, + IDBIndexType, + IDBKeyType, + IDBObjectStoreType, + 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<SerializedScriptValue> serializedScriptValue(); + + // Set can only be called once. + void set(); // For "null". + 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<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<SerializedScriptValue> m_serializedScriptValue; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBAny_h diff --git a/WebCore/storage/IDBAny.idl b/WebCore/storage/IDBAny.idl new file mode 100644 index 0000000..19d8424 --- /dev/null +++ b/WebCore/storage/IDBAny.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE, + CustomToJS + ] IDBAny { + // This space is intentionally left blank. + }; +} diff --git a/WebCore/storage/IDBCallbacks.h b/WebCore/storage/IDBCallbacks.h new file mode 100644 index 0000000..bc48477 --- /dev/null +++ b/WebCore/storage/IDBCallbacks.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. + * 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 "SerializedScriptValue.h" +#include <wtf/RefCounted.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class IDBCallbacks : public RefCounted<IDBCallbacks> { +public: + virtual ~IDBCallbacks() { } + + virtual void onError(PassRefPtr<IDBDatabaseError>) = 0; + virtual void onSuccess() = 0; // For "null". + virtual void onSuccess(PassRefPtr<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<SerializedScriptValue>) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBCallbacks_h diff --git a/WebCore/storage/IDBCursor.cpp b/WebCore/storage/IDBCursor.cpp new file mode 100644 index 0000000..de752f5 --- /dev/null +++ b/WebCore/storage/IDBCursor.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBCursor.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBAny.h" +#include "IDBCallbacks.h" +#include "IDBCursorBackendInterface.h" +#include "IDBKey.h" +#include "IDBRequest.h" +#include "ScriptExecutionContext.h" +#include "SerializedScriptValue.h" + +namespace WebCore { + +IDBCursor::IDBCursor(PassRefPtr<IDBCursorBackendInterface> backend) + : m_backend(backend) +{ +} + +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) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->update(value, request); + return request.release(); +} + +PassRefPtr<IDBRequest> IDBCursor::continueFunction(ScriptExecutionContext* context, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->continueFunction(key, request); + return request.release(); +} + +PassRefPtr<IDBRequest> IDBCursor::remove(ScriptExecutionContext* context) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->remove(request); + return request.release(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBCursor.h b/WebCore/storage/IDBCursor.h new file mode 100644 index 0000000..ccce001 --- /dev/null +++ b/WebCore/storage/IDBCursor.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBCursor_h +#define IDBCursor_h + +#if ENABLE(INDEXED_DATABASE) + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Threading.h> + +namespace WebCore { + +class IDBAny; +class IDBCallbacks; +class IDBCursorBackendInterface; +class IDBKey; +class IDBRequest; +class ScriptExecutionContext; +class SerializedScriptValue; + +class IDBCursor : public ThreadSafeShared<IDBCursor> { +public: + enum Direction { + NEXT = 0, + NEXT_NO_DUPLICATE = 1, + PREV = 2, + PREV_NO_DUPLICATE = 3, + }; + static PassRefPtr<IDBCursor> create(PassRefPtr<IDBCursorBackendInterface> backend) + { + return adoptRef(new IDBCursor(backend)); + } + virtual ~IDBCursor(); + + // Implement the IDL + virtual unsigned short direction() const; + virtual PassRefPtr<IDBKey> key() const; + virtual PassRefPtr<IDBAny> value() const; + virtual PassRefPtr<IDBRequest> update(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>); + virtual PassRefPtr<IDBRequest> continueFunction(ScriptExecutionContext*, PassRefPtr<IDBKey> = 0); + virtual PassRefPtr<IDBRequest> remove(ScriptExecutionContext*); + +private: + explicit IDBCursor(PassRefPtr<IDBCursorBackendInterface>); + + RefPtr<IDBCursorBackendInterface> m_backend; +}; + +} // namespace WebCore + +#endif + +#endif // IDBCursor_h diff --git a/WebCore/storage/IDBCursor.idl b/WebCore/storage/IDBCursor.idl new file mode 100644 index 0000000..3702ef3 --- /dev/null +++ b/WebCore/storage/IDBCursor.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: + * + * 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; + + [CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value); + [CallWith=ScriptExecutionContext, ImplementationFunction=continueFunction] IDBRequest continue(in [Optional] IDBKey key); + [CallWith=ScriptExecutionContext] IDBRequest remove(); + }; +} diff --git a/WebCore/storage/IDBCursorBackendImpl.cpp b/WebCore/storage/IDBCursorBackendImpl.cpp new file mode 100644 index 0000000..d3298b3 --- /dev/null +++ b/WebCore/storage/IDBCursorBackendImpl.cpp @@ -0,0 +1,89 @@ +/* + * 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 "IDBAny.h" +#include "IDBCallbacks.h" +#include "IDBKeyRange.h" +#include "IDBObjectStoreBackendImpl.h" +#include "IDBRequest.h" +#include "SQLiteDatabase.h" +#include "SerializedScriptValue.h" + +namespace WebCore { + +IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl> idbObjectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value) + : m_idbObjectStore(idbObjectStore) + , m_keyRange(keyRange) + , m_direction(direction) + , m_key(key) + , m_value(IDBAny::create(value.get())) +{ +} + +IDBCursorBackendImpl::~IDBCursorBackendImpl() +{ +} + +unsigned short IDBCursorBackendImpl::direction() const +{ + return m_direction; +} + +PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const +{ + return m_key; +} + +PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const +{ + return m_value; +} + +void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>) +{ + // FIXME: Implement this method. + ASSERT_NOT_REACHED(); +} + +void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) +{ + // FIXME: Implement this method. + ASSERT_NOT_REACHED(); +} + +void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks>) +{ + // FIXME: Implement this method. + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBCursorBackendImpl.h b/WebCore/storage/IDBCursorBackendImpl.h new file mode 100644 index 0000000..9ef62fe --- /dev/null +++ b/WebCore/storage/IDBCursorBackendImpl.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef IDBCursorBackendImpl_h +#define IDBCursorBackendImpl_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBCursor.h" +#include "IDBCursorBackendInterface.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBKeyRange; +class IDBObjectStoreBackendImpl; +class SerializedScriptValue; + +class IDBCursorBackendImpl : public IDBCursorBackendInterface { +public: + static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value) + { + return adoptRef(new IDBCursorBackendImpl(objectStore, keyRange, direction, key, value)); + } + virtual ~IDBCursorBackendImpl(); + + virtual unsigned short direction() const; + virtual PassRefPtr<IDBKey> key() const; + virtual PassRefPtr<IDBAny> value() const; + virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>); + virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); + virtual void remove(PassRefPtr<IDBCallbacks>); + +private: + IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassRefPtr<IDBKey>, PassRefPtr<SerializedScriptValue>); + + RefPtr<IDBObjectStoreBackendImpl> m_idbObjectStore; + RefPtr<IDBKeyRange> m_keyRange; + IDBCursor::Direction m_direction; + RefPtr<IDBKey> m_key; + RefPtr<IDBAny> m_value; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBCursorBackendImpl_h diff --git a/WebCore/storage/IDBCursorBackendInterface.h b/WebCore/storage/IDBCursorBackendInterface.h new file mode 100644 index 0000000..4b209c4 --- /dev/null +++ b/WebCore/storage/IDBCursorBackendInterface.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBCursorBackendInterface_h +#define IDBCursorBackendInterface_h + +#if ENABLE(INDEXED_DATABASE) + +#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>) = 0; + virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0; + virtual void remove(PassRefPtr<IDBCallbacks>) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBCursorBackendInterface_h diff --git a/WebCore/storage/IDBDatabase.cpp b/WebCore/storage/IDBDatabase.cpp new file mode 100644 index 0000000..78a6646 --- /dev/null +++ b/WebCore/storage/IDBDatabase.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 "IDBDatabase.h" + +#include "IDBAny.h" +#include "IDBFactoryBackendInterface.h" +#include "IDBObjectStore.h" +#include "IDBRequest.h" +#include "IDBTransaction.h" +#include "ScriptExecutionContext.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +IDBDatabase::IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface> backend) + : m_backend(backend) +{ + // We pass a reference to this object before it can be adopted. + relaxAdoptionRequirement(); +} + +IDBDatabase::~IDBDatabase() +{ +} + +PassRefPtr<IDBRequest> IDBDatabase::createObjectStore(ScriptExecutionContext* context, const String& name, const String& keyPath, bool autoIncrement) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->createObjectStore(name, keyPath, autoIncrement, request); + return request; +} + +PassRefPtr<IDBObjectStore> IDBDatabase::objectStore(const String& name, unsigned short mode) +{ + RefPtr<IDBObjectStoreBackendInterface> objectStore = m_backend->objectStore(name, mode); + ASSERT(objectStore); // FIXME: If this is null, we should raise a NOT_FOUND_ERR. + return IDBObjectStore::create(objectStore.release()); +} + +PassRefPtr<IDBRequest> IDBDatabase::removeObjectStore(ScriptExecutionContext* context, const String& name) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_backend->removeObjectStore(name, request); + return request; +} + +PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* context, DOMStringList* storeNames, unsigned short mode, unsigned long timeout) +{ + // 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, mode, timeout); + RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend, this); + transactionBackend->setCallbacks(transaction.get()); + return transaction.release(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBDatabase.h b/WebCore/storage/IDBDatabase.h new file mode 100644 index 0000000..0e83288 --- /dev/null +++ b/WebCore/storage/IDBDatabase.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 IDBDatabase_h +#define IDBDatabase_h + +#include "DOMStringList.h" +#include "IDBDatabaseBackendInterface.h" +#include "IDBTransaction.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class IDBAny; +class IDBObjectStore; +class IDBRequest; +class ScriptExecutionContext; + +class IDBDatabase : public RefCounted<IDBDatabase> { +public: + static PassRefPtr<IDBDatabase> create(PassRefPtr<IDBDatabaseBackendInterface> database) + { + return adoptRef(new IDBDatabase(database)); + } + ~IDBDatabase(); + + // Implement the IDL + String name() const { return m_backend->name(); } + String version() const { return m_backend->version(); } + PassRefPtr<DOMStringList> objectStores() const { return m_backend->objectStores(); } + + PassRefPtr<IDBRequest> createObjectStore(ScriptExecutionContext*, const String& name, const String& keyPath = String(), bool autoIncrement = false); + PassRefPtr<IDBObjectStore> objectStore(const String& name, unsigned short mode = IDBTransaction::READ_ONLY); + PassRefPtr<IDBRequest> removeObjectStore(ScriptExecutionContext*, const String& name); + PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext*, DOMStringList* storeNames = 0, unsigned short mode = IDBTransaction::READ_ONLY, + unsigned long timeout = 0); // FIXME: what should the default timeout be? +private: + IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface>); + + RefPtr<IDBDatabaseBackendInterface> m_backend; +}; + +} // namespace WebCore + +#endif + +#endif // IDBDatabase_h diff --git a/WebCore/storage/IDBDatabase.idl b/WebCore/storage/IDBDatabase.idl new file mode 100644 index 0000000..51bbafb --- /dev/null +++ b/WebCore/storage/IDBDatabase.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: + * + * 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 objectStores; + + // FIXME: Add setVersion. + + [CallWith=ScriptExecutionContext] IDBRequest createObjectStore(in DOMString name, in [Optional, ConvertNullToNullString] DOMString keyPath, in [Optional] boolean autoIncrement); + // FIXME: objectStore needs to be able to raise an IDBDatabaseException. + IDBObjectStore objectStore(in DOMString name, in [Optional] unsigned short mode); + [CallWith=ScriptExecutionContext] IDBRequest removeObjectStore(in DOMString name); + [CallWith=ScriptExecutionContext] IDBTransaction transaction (in [Optional] DOMStringList storeNames, in [Optional] unsigned short mode, in [Optional] unsigned long timeout); + }; + +} diff --git a/WebCore/storage/IDBDatabaseBackendImpl.cpp b/WebCore/storage/IDBDatabaseBackendImpl.cpp new file mode 100644 index 0000000..23bc44e --- /dev/null +++ b/WebCore/storage/IDBDatabaseBackendImpl.cpp @@ -0,0 +1,211 @@ +/* + * 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" + +#include "DOMStringList.h" +#include "IDBDatabaseException.h" +#include "IDBObjectStoreBackendImpl.h" +#include "IDBTransactionCoordinator.h" +#include "SQLiteDatabase.h" +#include "SQLiteStatement.h" +#include "SQLiteTransaction.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +static bool extractMetaData(SQLiteDatabase* sqliteDatabase, const String& expectedName, String& foundDescription, String& foundVersion) +{ + SQLiteStatement metaDataQuery(*sqliteDatabase, "SELECT name, description, version FROM MetaData"); + if (metaDataQuery.prepare() != SQLResultOk || metaDataQuery.step() != SQLResultRow) + return false; + + if (metaDataQuery.getColumnText(0) != expectedName) { + LOG_ERROR("Name in MetaData (%s) doesn't match expected (%s) for IndexedDB", metaDataQuery.getColumnText(0).utf8().data(), expectedName.utf8().data()); + ASSERT_NOT_REACHED(); + } + foundDescription = metaDataQuery.getColumnText(1); + foundVersion = metaDataQuery.getColumnText(2); + + if (metaDataQuery.step() == SQLResultRow) { + LOG_ERROR("More than one row found in MetaData table"); + ASSERT_NOT_REACHED(); + } + + return true; +} + +static bool setMetaData(SQLiteDatabase* sqliteDatabase, const String& name, const String& description, const String& version) +{ + ASSERT(!name.isNull() && !description.isNull() && !version.isNull()); + + sqliteDatabase->executeCommand("DELETE FROM MetaData"); + + SQLiteStatement insert(*sqliteDatabase, "INSERT INTO MetaData (name, description, version) VALUES (?, ?, ?)"); + if (insert.prepare() != SQLResultOk) { + LOG_ERROR("Failed to prepare MetaData insert statement for IndexedDB"); + return false; + } + + insert.bindText(1, name); + insert.bindText(2, description); + insert.bindText(3, version); + + if (insert.step() != SQLResultDone) { + LOG_ERROR("Failed to insert row into MetaData for IndexedDB"); + return false; + } + + // FIXME: Should we assert there's only one row? + + return true; +} + +IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> sqliteDatabase, IDBTransactionCoordinator* coordinator) + : m_sqliteDatabase(sqliteDatabase) + , m_name(name) + , m_version("") + , m_transactionCoordinator(coordinator) +{ + ASSERT(!m_name.isNull()); + + // FIXME: The spec is in flux about how to handle description. Sync it up once a final decision is made. + String foundDescription = ""; + bool result = extractMetaData(m_sqliteDatabase.get(), m_name, foundDescription, m_version); + m_description = description.isNull() ? foundDescription : description; + + if (!result || m_description != foundDescription) + setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version); + + loadObjectStores(); +} + +IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl() +{ +} + +void IDBDatabaseBackendImpl::setDescription(const String& description) +{ + if (description == m_description) + return; + + m_description = description; + setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version); +} + +PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStores() const +{ + RefPtr<DOMStringList> objectStoreNames = DOMStringList::create(); + for (ObjectStoreMap::const_iterator it = m_objectStores.begin(); it != m_objectStores.end(); ++it) + objectStoreNames->append(it->first); + return objectStoreNames.release(); +} + +void IDBDatabaseBackendImpl::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks> callbacks) +{ + if (m_objectStores.contains(name)) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "An objectStore with that name already exists.")); + return; + } + + SQLiteStatement insert(sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement) VALUES (?, ?, ?)"); + bool ok = insert.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + insert.bindText(1, name); + insert.bindText(2, keyPath); + insert.bindInt(3, static_cast<int>(autoIncrement)); + ok = insert.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + int64_t id = sqliteDatabase().lastInsertRowID(); + + RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement); + ASSERT(objectStore->name() == name); + m_objectStores.set(name, objectStore); + callbacks->onSuccess(objectStore.get()); +} + +PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name, unsigned short mode) +{ + // FIXME: If no transaction is running, this should implicitly start one. + ASSERT_UNUSED(mode, !mode); // FIXME: Handle non-standard modes. + return m_objectStores.get(name); +} + +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::removeObjectStore(const String& name, PassRefPtr<IDBCallbacks> callbacks) +{ + RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name); + if (!objectStore) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "No objectStore with that name exists.")); + return; + } + + SQLiteTransaction transaction(sqliteDatabase()); + transaction.begin(); + doDelete(sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id()); + doDelete(sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id()); + doDelete(sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id()); + // FIXME: Delete index data as well. + transaction.commit(); + + m_objectStores.remove(name); + callbacks->onSuccess(); +} + +PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout) +{ + return m_transactionCoordinator->createTransaction(objectStores, mode, timeout, this); +} + +void IDBDatabaseBackendImpl::loadObjectStores() +{ + SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores"); + bool ok = objectStoresQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + 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(this, id, name, keyPath, autoIncrement)); + } +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBDatabaseBackendImpl.h b/WebCore/storage/IDBDatabaseBackendImpl.h new file mode 100644 index 0000000..3540b21 --- /dev/null +++ b/WebCore/storage/IDBDatabaseBackendImpl.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 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 IDBObjectStoreBackendImpl; +class IDBTransactionCoordinator; +class SQLiteDatabase; + +class IDBDatabaseBackendImpl : public IDBDatabaseBackendInterface { +public: + static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator* coordinator) + { + return adoptRef(new IDBDatabaseBackendImpl(name, description, database, coordinator)); + } + virtual ~IDBDatabaseBackendImpl(); + + void setDescription(const String& description); + SQLiteDatabase& sqliteDatabase() const { return *m_sqliteDatabase.get(); } + + // Implements IDBDatabase + virtual String name() const { return m_name; } + virtual String description() const { return m_description; } + virtual String version() const { return m_version; } + virtual PassRefPtr<DOMStringList> objectStores() const; + + virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>); + virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, unsigned short mode); + virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>); + virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout); +private: + IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator*); + + void loadObjectStores(); + + OwnPtr<SQLiteDatabase> m_sqliteDatabase; + String m_name; + String m_description; + String m_version; + + typedef HashMap<String, RefPtr<IDBObjectStoreBackendImpl> > ObjectStoreMap; + ObjectStoreMap m_objectStores; + + RefPtr<IDBTransactionCoordinator> m_transactionCoordinator; +}; + +} // namespace WebCore + +#endif + +#endif // IDBDatabaseBackendImpl_h diff --git a/WebCore/storage/IDBDatabaseBackendInterface.h b/WebCore/storage/IDBDatabaseBackendInterface.h new file mode 100644 index 0000000..9e35369 --- /dev/null +++ b/WebCore/storage/IDBDatabaseBackendInterface.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 IDBDatabaseBackendInterface_h +#define IDBDatabaseBackendInterface_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 description() const = 0; + virtual String version() const = 0; + virtual PassRefPtr<DOMStringList> objectStores() const = 0; + + // FIXME: Add transaction and setVersion. + + virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>) = 0; + virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, unsigned short mode) = 0; + virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>) = 0; + virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBDatabaseBackendInterface_h diff --git a/WebCore/storage/IDBDatabaseError.h b/WebCore/storage/IDBDatabaseError.h index e8fd2dd..c345ff9 100644 --- a/WebCore/storage/IDBDatabaseError.h +++ b/WebCore/storage/IDBDatabaseError.h @@ -10,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef IDBDatabaseError_h #define IDBDatabaseError_h @@ -38,19 +36,20 @@ namespace WebCore { class IDBDatabaseError : public RefCounted<IDBDatabaseError> { public: - static PassRefPtr<IDBDatabaseError> create() + static PassRefPtr<IDBDatabaseError> create(unsigned short code, const String& message) { - return adoptRef(new IDBDatabaseError()); + return adoptRef(new IDBDatabaseError(code, message)); } ~IDBDatabaseError() { } unsigned short code() const { return m_code; } void setCode(unsigned short value) { m_code = value; } - String message() const { return m_message; } + const String& message() const { return m_message; } void setMessage(const String& value) { m_message = value; } private: - IDBDatabaseError() { } + IDBDatabaseError(unsigned short code, const String& message) + : m_code(code), m_message(message) { } unsigned short m_code; String m_message; @@ -61,4 +60,3 @@ private: #endif #endif // IDBDatabaseError_h - diff --git a/WebCore/storage/IDBDatabaseError.idl b/WebCore/storage/IDBDatabaseError.idl index 6c6019c..2912a1d 100644 --- a/WebCore/storage/IDBDatabaseError.idl +++ b/WebCore/storage/IDBDatabaseError.idl @@ -10,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + module storage { interface [ diff --git a/WebCore/storage/IDBDatabaseException.h b/WebCore/storage/IDBDatabaseException.h index d94a7f9..251cfc9 100644 --- a/WebCore/storage/IDBDatabaseException.h +++ b/WebCore/storage/IDBDatabaseException.h @@ -10,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef IDBDatabaseException_h #define IDBDatabaseException_h @@ -43,7 +41,22 @@ public: return adoptRef(new IDBDatabaseException()); } ~IDBDatabaseException() { } - + + // Keep in sync with what's in the .idl file. + enum ErrorCode { + UNKNOWN_ERR = 0, + NON_TRANSIENT_ERR = 1, + NOT_FOUND_ERR = 2, + CONSTRAINT_ERR = 3, + DATA_ERR = 4, + NOT_ALLOWED_ERR = 5, + SERIAL_ERR = 11, + RECOVERABLE_ERR = 21, + TRANSIENT_ERR = 31, + TIMEOUT_ERR = 32, + DEADLOCK_ERR = 33 + }; + unsigned short code() const { return m_code; } void setCode(unsigned short value) { m_code = value; } String message() const { return m_message; } @@ -61,4 +74,3 @@ private: #endif #endif // IDBDatabaseException_h - diff --git a/WebCore/storage/IDBDatabaseException.idl b/WebCore/storage/IDBDatabaseException.idl index 898e5f9..88e6e7e 100644 --- a/WebCore/storage/IDBDatabaseException.idl +++ b/WebCore/storage/IDBDatabaseException.idl @@ -10,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -25,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + module storage { interface [ @@ -41,6 +39,7 @@ module storage { const unsigned short TRANSIENT_ERR = 31; const unsigned short TIMEOUT_ERR = 32; const unsigned short DEADLOCK_ERR = 33; + attribute unsigned short code; attribute DOMString message; }; diff --git a/WebCore/storage/IDBErrorEvent.cpp b/WebCore/storage/IDBErrorEvent.cpp new file mode 100644 index 0000000..cba980d --- /dev/null +++ b/WebCore/storage/IDBErrorEvent.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBErrorEvent.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "EventNames.h" +#include "IDBAny.h" +#include "IDBDatabaseError.h" + +namespace WebCore { + +PassRefPtr<IDBErrorEvent> IDBErrorEvent::create(PassRefPtr<IDBAny> source, const IDBDatabaseError& error) +{ + return adoptRef(new IDBErrorEvent(source, error)); +} + +IDBErrorEvent::IDBErrorEvent(PassRefPtr<IDBAny> source, const IDBDatabaseError& error) + : IDBEvent(eventNames().errorEvent, source) + , m_code(error.code()) + , m_message(error.message()) +{ +} + +IDBErrorEvent::~IDBErrorEvent() +{ +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBErrorEvent.h b/WebCore/storage/IDBErrorEvent.h new file mode 100644 index 0000000..648da8b --- /dev/null +++ b/WebCore/storage/IDBErrorEvent.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBErrorEvent_h +#define IDBErrorEvent_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBEvent.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBAny; +class IDBDatabaseError; + +class IDBErrorEvent : public IDBEvent { +public: + static PassRefPtr<IDBErrorEvent> create(PassRefPtr<IDBAny> source, const IDBDatabaseError&); + // FIXME: Need to allow creation of these events from JS. + virtual ~IDBErrorEvent(); + + unsigned short code() const { return m_code; } + String message() { return m_message; } + + virtual bool isIDBErrorEvent() const { return true; } + +private: + IDBErrorEvent(PassRefPtr<IDBAny> source, const IDBDatabaseError&); + + unsigned short m_code; + String m_message; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBEvent_h diff --git a/WebCore/storage/IndexedDatabaseRequest.idl b/WebCore/storage/IDBErrorEvent.idl index b1fc7da..5c58f6f 100644 --- a/WebCore/storage/IndexedDatabaseRequest.idl +++ b/WebCore/storage/IDBErrorEvent.idl @@ -25,14 +25,13 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + module storage { interface [ Conditional=INDEXED_DATABASE - ] IndexedDatabaseRequest { - readonly attribute IDBRequest request; - [Custom] void open(in DOMString name, in DOMString description, in optional boolean modifyDatabase) - raises(IDBDatabaseException); + ] IDBErrorEvent : IDBEvent { + readonly attribute unsigned short code; + readonly attribute DOMString message; }; - } diff --git a/WebCore/storage/IDBEvent.cpp b/WebCore/storage/IDBEvent.cpp new file mode 100644 index 0000000..f9f6060 --- /dev/null +++ b/WebCore/storage/IDBEvent.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBEvent.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBAny.h" + +namespace WebCore { + +IDBEvent::IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source) + : Event(type, false, false) + , m_source(source) +{ +} + +IDBEvent::~IDBEvent() +{ +} + +PassRefPtr<IDBAny> IDBEvent::source() +{ + return m_source; +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBEvent.h b/WebCore/storage/IDBEvent.h new file mode 100644 index 0000000..c44e449 --- /dev/null +++ b/WebCore/storage/IDBEvent.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBEvent_h +#define IDBEvent_h + +#if ENABLE(INDEXED_DATABASE) + +#include "Event.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBAny; + +class IDBEvent : public Event { +public: + virtual ~IDBEvent(); + + PassRefPtr<IDBAny> source(); + +protected: + IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source); + +private: + RefPtr<IDBAny> m_source; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBEvent_h diff --git a/WebCore/storage/IDBEvent.idl b/WebCore/storage/IDBEvent.idl new file mode 100644 index 0000000..4dd552e --- /dev/null +++ b/WebCore/storage/IDBEvent.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBEvent : Event { + readonly attribute IDBAny source; + }; +} diff --git a/WebCore/storage/IDBFactory.cpp b/WebCore/storage/IDBFactory.cpp new file mode 100644 index 0000000..d3a83a5 --- /dev/null +++ b/WebCore/storage/IDBFactory.cpp @@ -0,0 +1,74 @@ +/* + * 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" + +#include "DOMStringList.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "IDBDatabase.h" +#include "IDBFactoryBackendInterface.h" +#include "IDBKeyRange.h" +#include "IDBRequest.h" + +#if ENABLE(INDEXED_DATABASE) + +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, const String& description) +{ + if (!context->isDocument()) { + // FIXME: make this work with workers. + return 0; + } + + Document* document = static_cast<Document*>(context); + if (!document->frame()) + return 0; + + RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this)); + m_factoryBackend->open(name, description, request, document->securityOrigin(), document->frame()); + return request; +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IndexedDatabaseRequest.h b/WebCore/storage/IDBFactory.h index 74aada3..a96aa38 100644 --- a/WebCore/storage/IndexedDatabaseRequest.h +++ b/WebCore/storage/IDBFactory.h @@ -25,10 +25,12 @@ * (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 IndexedDatabaseRequest_h -#define IndexedDatabaseRequest_h +#ifndef IDBFactory_h +#define IDBFactory_h +#include "DOMStringList.h" #include "ExceptionCode.h" +#include "IDBFactoryBackendInterface.h" #include "PlatformString.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -38,28 +40,31 @@ namespace WebCore { +class IDBKey; +class IDBKeyRange; class IDBRequest; +class IDBFactoryBackendInterface; +class ScriptExecutionContext; -class IndexedDatabaseRequest : public RefCounted<IndexedDatabaseRequest> { +class IDBFactory : public RefCounted<IDBFactory> { public: - static PassRefPtr<IndexedDatabaseRequest> create() + static PassRefPtr<IDBFactory> create(IDBFactoryBackendInterface* factory) { - return adoptRef(new IndexedDatabaseRequest()); + return adoptRef(new IDBFactory(factory)); } - ~IndexedDatabaseRequest(); + ~IDBFactory(); - IDBRequest* request() const { return m_request.get(); } - void open(const String& name, const String& description, bool modifyDatabase, ExceptionCode&); + PassRefPtr<IDBRequest> open(ScriptExecutionContext*, const String& name, const String& description = String()); private: - IndexedDatabaseRequest(); + IDBFactory(IDBFactoryBackendInterface*); - PassRefPtr<IDBRequest> m_request; + RefPtr<IDBFactoryBackendInterface> m_factoryBackend; }; } // namespace WebCore #endif -#endif // IndexedDatabaseRequest_h +#endif // IDBFactory_h diff --git a/WebCore/storage/IDBFactory.idl b/WebCore/storage/IDBFactory.idl new file mode 100644 index 0000000..215d67c --- /dev/null +++ b/WebCore/storage/IDBFactory.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 + ] IDBFactory { + [CallWith=ScriptExecutionContext] IDBRequest open(in DOMString name, in [Optional, ConvertUndefinedOrNullToNullString] DOMString description); + }; + +} diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp new file mode 100644 index 0000000..d656128 --- /dev/null +++ b/WebCore/storage/IDBFactoryBackendImpl.cpp @@ -0,0 +1,143 @@ +/* + * 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 "IDBTransactionCoordinator.h" +#include "SQLiteDatabase.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() +{ +} + +static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name) +{ + String pathBase = "/tmp/temporary-indexed-db-files"; // FIXME: Write a PageGroupSettings class and have this value come from that. + 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; + } + + String databaseIdentifier = securityOrigin->databaseIdentifier(); + String santizedName = encodeForFileName(name); + String path = pathByAppendingComponent(pathBase, databaseIdentifier + "_" + santizedName + ".indexeddb"); + + OwnPtr<SQLiteDatabase> sqliteDatabase = adoptPtr(new SQLiteDatabase()); + if (!sqliteDatabase->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; + } + + return sqliteDatabase.release(); +} + +static bool createTables(SQLiteDatabase* sqliteDatabase) +{ + // FIXME: Remove all the drop table commands once the on disk structure stabilizes. + static const char* commands[] = { + "DROP TABLE IF EXISTS MetaData", + "CREATE TABLE IF NOT EXISTS MetaData (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)", + + "DROP TABLE IF EXISTS ObjectStores", + "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL)", + "DROP INDEX IF EXISTS ObjectStores_name", + "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_name ON ObjectStores(name)", + + "DROP TABLE IF EXISTS Indexes", + "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)", + "DROP INDEX IF EXISTS Indexes_composit", + "CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectStoreId, name)", + + "DROP TABLE IF EXISTS ObjectStoreData", + "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)", + "DROP INDEX IF EXISTS ObjectStoreData_composit", + "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)" + }; + + 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; + } + } + return true; +} + +void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*) +{ + IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(name); + if (it != m_databaseBackendMap.end()) { + if (!description.isNull()) + it->second->setDescription(description); // The description may have changed. + callbacks->onSuccess(it->second.get()); + return; + } + + // FIXME: Everything from now on should be done on another thread. + + OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name); + if (!sqliteDatabase || !createTables(sqliteDatabase.get())) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error.")); + return; + } + + RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, description, sqliteDatabase.release(), m_transactionCoordinator.get()); + callbacks->onSuccess(databaseBackend.get()); + m_databaseBackendMap.set(name, databaseBackend.release()); +} + +void IDBFactoryBackendImpl::abortPendingTransactions(const Vector<int>& pendingIDs) +{ + for (size_t i = 0; i < pendingIDs.size(); ++i) + m_transactionCoordinator->abort(pendingIDs.at(i)); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + diff --git a/WebCore/storage/IDBFactoryBackendImpl.h b/WebCore/storage/IDBFactoryBackendImpl.h new file mode 100644 index 0000000..c9a33da --- /dev/null +++ b/WebCore/storage/IDBFactoryBackendImpl.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 IDBTransactionCoordinator; + +class IDBFactoryBackendImpl : public IDBFactoryBackendInterface { +public: + static PassRefPtr<IDBFactoryBackendImpl> create() + { + return adoptRef(new IDBFactoryBackendImpl()); + } + virtual ~IDBFactoryBackendImpl(); + + virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*); + virtual void abortPendingTransactions(const Vector<int>& pendingIDs); + +private: + IDBFactoryBackendImpl(); + + typedef HashMap<String, RefPtr<IDBDatabaseBackendImpl> > IDBDatabaseBackendMap; + IDBDatabaseBackendMap m_databaseBackendMap; + RefPtr<IDBTransactionCoordinator> m_transactionCoordinator; + + // We only create one instance of this class at a time. + static IDBFactoryBackendImpl* idbFactoryBackendImpl; +}; + +} // namespace WebCore + +#endif + +#endif // IDBFactoryBackendImpl_h + diff --git a/WebCore/storage/IDBFactoryBackendInterface.cpp b/WebCore/storage/IDBFactoryBackendInterface.cpp new file mode 100644 index 0000000..f1c0fb7 --- /dev/null +++ b/WebCore/storage/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 "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(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + diff --git a/WebCore/storage/IDBFactoryBackendInterface.h b/WebCore/storage/IDBFactoryBackendInterface.h new file mode 100644 index 0000000..c052bc2 --- /dev/null +++ b/WebCore/storage/IDBFactoryBackendInterface.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. + * 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, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*) = 0; + virtual void abortPendingTransactions(const Vector<int>& ids) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBFactoryBackendInterface_h + diff --git a/WebCore/storage/IDBIndex.cpp b/WebCore/storage/IDBIndex.cpp new file mode 100644 index 0000000..62c1da8 --- /dev/null +++ b/WebCore/storage/IDBIndex.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBIndex.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend) + : m_backend(backend) +{ +} + +IDBIndex::~IDBIndex() +{ +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBIndex.h b/WebCore/storage/IDBIndex.h new file mode 100644 index 0000000..5e716b7 --- /dev/null +++ b/WebCore/storage/IDBIndex.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBIndex_h +#define IDBIndex_h + +#include "IDBIndexBackendInterface.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) + { + return adoptRef(new IDBIndex(backend)); + } + ~IDBIndex(); + + // Implement the IDL + String name() const { return m_backend->name(); } + String keyPath() const { return m_backend->keyPath(); } + bool unique() const { return m_backend->unique(); } + +private: + IDBIndex(PassRefPtr<IDBIndexBackendInterface>); + + RefPtr<IDBIndexBackendInterface> m_backend; +}; + +} // namespace WebCore + +#endif + +#endif // IDBIndex_h diff --git a/WebCore/storage/IDBIndex.idl b/WebCore/storage/IDBIndex.idl new file mode 100644 index 0000000..e796b03 --- /dev/null +++ b/WebCore/storage/IDBIndex.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBIndex { + // FIXME: Complete this file. + + readonly attribute DOMString name; + readonly attribute DOMString keyPath; + readonly attribute boolean unique; + }; + +} diff --git a/WebCore/storage/IDBIndexBackendImpl.cpp b/WebCore/storage/IDBIndexBackendImpl.cpp new file mode 100644 index 0000000..180ff1d --- /dev/null +++ b/WebCore/storage/IDBIndexBackendImpl.cpp @@ -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. + * + * 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 "IDBDatabaseBackendImpl.h" +#include "IDBObjectStoreBackendImpl.h" +#include "SQLiteDatabase.h" + +namespace WebCore { + +IDBIndexBackendImpl::IDBIndexBackendImpl(IDBObjectStoreBackendImpl* objectStore, int64_t id, const String& name, const String& keyPath, bool unique) + : m_objectStore(objectStore) + , m_id(id) + , m_name(name) + , m_keyPath(keyPath) + , m_unique(unique) +{ +} + +IDBIndexBackendImpl::~IDBIndexBackendImpl() +{ +} + +SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const +{ + return m_objectStore->database()->sqliteDatabase(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBIndexBackendImpl.h b/WebCore/storage/IDBIndexBackendImpl.h new file mode 100644 index 0000000..acf6b1f --- /dev/null +++ b/WebCore/storage/IDBIndexBackendImpl.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 IDBIndexBackendImpl_h +#define IDBIndexBackendImpl_h + +#include "IDBIndexBackendInterface.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class IDBObjectStoreBackendImpl; +class SQLiteDatabase; + +class IDBIndexBackendImpl : public IDBIndexBackendInterface { +public: + static PassRefPtr<IDBIndexBackendImpl> create(IDBObjectStoreBackendImpl* objectStore, int64_t id, const String& name, const String& keyPath, bool unique) + { + return adoptRef(new IDBIndexBackendImpl(objectStore, id, name, keyPath, unique)); + } + virtual ~IDBIndexBackendImpl(); + + // Implements IDBIndexBackendInterface. + virtual String name() { return m_name; } + virtual String keyPath() { return m_keyPath; } + virtual bool unique() { return m_unique; } + +private: + IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, int64_t id, const String& name, const String& keyPath, bool unique); + + SQLiteDatabase& sqliteDatabase() const; + + RefPtr<IDBObjectStoreBackendImpl> m_objectStore; + + int64_t m_id; + String m_name; + String m_keyPath; + bool m_unique; +}; + +} // namespace WebCore + +#endif + +#endif // IDBIndexBackendImpl_h diff --git a/WebCore/storage/IDBIndexBackendInterface.h b/WebCore/storage/IDBIndexBackendInterface.h new file mode 100644 index 0000000..0d1ea34 --- /dev/null +++ b/WebCore/storage/IDBIndexBackendInterface.h @@ -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. + * + * 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 "PlatformString.h" +#include <wtf/Forward.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> { +public: + virtual ~IDBIndexBackendInterface() { } + + virtual String name() = 0; + virtual String keyPath() = 0; + virtual bool unique() = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBIndexBackendInterface_h diff --git a/WebCore/storage/IDBKey.cpp b/WebCore/storage/IDBKey.cpp new file mode 100644 index 0000000..8ec5dfd --- /dev/null +++ b/WebCore/storage/IDBKey.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBKey.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "SerializedScriptValue.h" + +namespace WebCore { + +IDBKey::IDBKey() + : m_type(NullType) +{ +} + +IDBKey::IDBKey(int32_t number) + : m_type(NumberType) + , m_number(number) +{ +} + +IDBKey::IDBKey(const String& string) + : m_type(StringType) + , m_string(string) +{ +} + +IDBKey::~IDBKey() +{ +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBKey.h b/WebCore/storage/IDBKey.h new file mode 100644 index 0000000..a84ea6a --- /dev/null +++ b/WebCore/storage/IDBKey.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBKey_h +#define IDBKey_h + +#include "PlatformString.h" +#include <wtf/Forward.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +// FIXME: Add dates. +class IDBKey : public RefCounted<IDBKey> { +public: + static PassRefPtr<IDBKey> create() + { + return adoptRef(new IDBKey()); + } + static PassRefPtr<IDBKey> create(int32_t number) + { + return adoptRef(new IDBKey(number)); + } + static PassRefPtr<IDBKey> create(const String& string) + { + return adoptRef(new IDBKey(string)); + } + ~IDBKey(); + + // In order of the least to the highest precedent in terms of sort order. + enum Type { + NullType = 0, + StringType, + NumberType + }; + + Type type() const { return m_type; } + + const String& string() const + { + ASSERT(m_type == StringType); + return m_string; + } + + int32_t number() const + { + ASSERT(m_type == NumberType); + return m_number; + } + +private: + IDBKey(); + explicit IDBKey(int32_t); + explicit IDBKey(const String&); + + Type m_type; + String m_string; + int32_t m_number; +}; + +} + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBKey_h diff --git a/WebCore/storage/IDBKey.idl b/WebCore/storage/IDBKey.idl new file mode 100644 index 0000000..04995f3 --- /dev/null +++ b/WebCore/storage/IDBKey.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE, + CustomToJS + ] IDBKey { + // This space is intentionally left blank. + }; +} diff --git a/WebCore/storage/IDBKeyPath.cpp b/WebCore/storage/IDBKeyPath.cpp new file mode 100644 index 0000000..8833da0 --- /dev/null +++ b/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/WebCore/storage/IDBKeyPath.h b/WebCore/storage/IDBKeyPath.h new file mode 100644 index 0000000..7787980 --- /dev/null +++ b/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/WebCore/storage/IDBKeyPathBackendImpl.cpp b/WebCore/storage/IDBKeyPathBackendImpl.cpp new file mode 100644 index 0000000..6cc9be5 --- /dev/null +++ b/WebCore/storage/IDBKeyPathBackendImpl.cpp @@ -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. + * + * 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 + +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. +} diff --git a/WebCore/storage/IDBKeyPathBackendImpl.h b/WebCore/storage/IDBKeyPathBackendImpl.h new file mode 100644 index 0000000..32af5e3 --- /dev/null +++ b/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/WebCore/storage/IDBKeyRange.cpp b/WebCore/storage/IDBKeyRange.cpp new file mode 100644 index 0000000..dfcae19 --- /dev/null +++ b/WebCore/storage/IDBKeyRange.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBKeyRange.h" + +#include "IDBKey.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +IDBKeyRange::IDBKeyRange(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags) + : m_left(left) + , m_right(right) + , m_flags(flags) +{ +} + +PassRefPtr<IDBKeyRange> IDBKeyRange::only(PassRefPtr<IDBKey> prpValue) +{ + RefPtr<IDBKey> value = prpValue; + return IDBKeyRange::create(value, value, IDBKeyRange::SINGLE); +} + +PassRefPtr<IDBKeyRange> IDBKeyRange::leftBound(PassRefPtr<IDBKey> bound, bool open) +{ + return IDBKeyRange::create(bound, IDBKey::create(), open ? IDBKeyRange::LEFT_OPEN : IDBKeyRange::LEFT_BOUND); +} + +PassRefPtr<IDBKeyRange> IDBKeyRange::rightBound(PassRefPtr<IDBKey> bound, bool open) +{ + return IDBKeyRange::create(IDBKey::create(), bound, open ? IDBKeyRange::RIGHT_OPEN : IDBKeyRange::RIGHT_BOUND); +} + +PassRefPtr<IDBKeyRange> IDBKeyRange::bound(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, bool openLeft, bool openRight) +{ + unsigned short flags = openLeft ? IDBKeyRange::LEFT_OPEN : IDBKeyRange::LEFT_BOUND; + flags |= openRight ? IDBKeyRange::RIGHT_OPEN : IDBKeyRange::RIGHT_BOUND; + return IDBKeyRange::create(left, right, flags); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBKeyRange.h b/WebCore/storage/IDBKeyRange.h new file mode 100644 index 0000000..5a426b7 --- /dev/null +++ b/WebCore/storage/IDBKeyRange.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 IDBKeyRange_h +#define IDBKeyRange_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBKey.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class IDBKeyRange : public RefCounted<IDBKeyRange> { +public: + // Keep in sync with what's in the .idl file. + enum Flags { + SINGLE = 0, + LEFT_OPEN = 1, + RIGHT_OPEN = 2, + LEFT_BOUND = 4, + RIGHT_BOUND = 8, + }; + + static PassRefPtr<IDBKeyRange> create(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags) + { + return adoptRef(new IDBKeyRange(left, right, flags)); + } + + ~IDBKeyRange() { } + + + PassRefPtr<IDBKey> left() const { return m_left; } + PassRefPtr<IDBKey> right() const { return m_right; } + unsigned short flags() const { return m_flags; } + + static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value); + static PassRefPtr<IDBKeyRange> leftBound(PassRefPtr<IDBKey> bound, bool open = false); + static PassRefPtr<IDBKeyRange> rightBound(PassRefPtr<IDBKey> bound, bool open = false); + static PassRefPtr<IDBKeyRange> bound(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, bool openLeft = false, bool openRight = false); + +private: + IDBKeyRange(PassRefPtr<IDBKey> left, PassRefPtr<IDBKey> right, unsigned short flags); + + RefPtr<IDBKey> m_left; + RefPtr<IDBKey> m_right; + unsigned short m_flags; +}; + +} // namespace WebCore + +#endif + +#endif // IDBKeyRange_h diff --git a/WebCore/storage/IDBKeyRange.idl b/WebCore/storage/IDBKeyRange.idl new file mode 100644 index 0000000..6daaec1 --- /dev/null +++ b/WebCore/storage/IDBKeyRange.idl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBKeyRange { + // Keep in sync with what's in the .h file. + const unsigned short SINGLE = 0; + const unsigned short LEFT_OPEN = 1; + const unsigned short RIGHT_OPEN = 2; + const unsigned short LEFT_BOUND = 4; + const unsigned short RIGHT_BOUND = 8; + + readonly attribute IDBKey left; + readonly attribute IDBKey right; + readonly attribute unsigned short flags; + + IDBKeyRange only(in IDBKey value); + IDBKeyRange leftBound(in IDBKey bound, in [Optional] boolean open); + IDBKeyRange rightBound(in IDBKey bound, in [Optional] boolean open); + IDBKeyRange bound(in IDBKey left, in IDBKey right, in [Optional] boolean openLeft, in [Optional] boolean openRight); + }; + +} diff --git a/WebCore/storage/IDBKeyTree.h b/WebCore/storage/IDBKeyTree.h new file mode 100644 index 0000000..70d6f83 --- /dev/null +++ b/WebCore/storage/IDBKeyTree.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBKeyTree_h +#define IDBKeyTree_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBKey.h" +#include <wtf/AVLTree.h> +#include <wtf/Vector.h> + +namespace WebCore { + +template <typename ValueType> +class IDBKeyTree : public RefCounted<IDBKeyTree<ValueType> > { +public: + static PassRefPtr<IDBKeyTree> create() + { + return adoptRef(new IDBKeyTree()); + } + ~IDBKeyTree(); + + ValueType* get(IDBKey* key); + void put(IDBKey* key, ValueType* value); + void remove(IDBKey* key); + +private: + struct TreeNode { + RefPtr<ValueType> value; + RefPtr<IDBKey> key; + + TreeNode* less; + TreeNode* greater; + int balanceFactor; + }; + + struct AVLTreeAbstractor { + typedef TreeNode* handle; + typedef size_t size; + typedef IDBKey* key; + + handle get_less(handle h) { return h->less; } + void set_less(handle h, handle lh) { h->less = lh; } + handle get_greater(handle h) { return h->greater; } + void set_greater(handle h, handle gh) { h->greater = gh; } + int get_balance_factor(handle h) { return h->balanceFactor; } + void set_balance_factor(handle h, int bf) { h->balanceFactor = bf; } + + static handle null() { return 0; } + + int compare_key_key(key va, key vb); + int compare_key_node(key k, handle h) { return compare_key_key(k, h->key.get()); } + int compare_node_node(handle h1, handle h2) { return compare_key_key(h1->key.get(), h2->key.get()); } + }; + + IDBKeyTree(); + + typedef WTF::AVLTree<AVLTreeAbstractor> TreeType; + TreeType m_tree; +}; + +template <typename ValueType> +IDBKeyTree<ValueType>::IDBKeyTree() +{ +} + +template <typename ValueType> +IDBKeyTree<ValueType>::~IDBKeyTree() +{ + typename TreeType::Iterator iter; + iter.start_iter_least(m_tree); + for (; *iter; ++iter) + delete *iter; + m_tree.purge(); +} + +template <typename ValueType> +int IDBKeyTree<ValueType>::AVLTreeAbstractor::compare_key_key(key va, key vb) +{ + if (va->type() != vb->type()) + return vb->type() - va->type(); + + switch (va->type()) { + case IDBKey::NullType: + return 0; + case IDBKey::NumberType: + return vb->number() - va->number(); + case IDBKey::StringType: + return codePointCompare(va->string(), vb->string()); + // FIXME: Handle dates. Oh, and test this thoroughly. + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +template <typename ValueType> +ValueType* IDBKeyTree<ValueType>::get(IDBKey* key) +{ + TreeNode* node = m_tree.search(key); + if (!node) + return 0; + return node->value.get(); +} + +template <typename ValueType> +void IDBKeyTree<ValueType>::put(IDBKey* key, ValueType* value) +{ + TreeNode* node = m_tree.search(key); + if (!node) { + node = new TreeNode(); + node->key = key; + m_tree.insert(node); + } + node->value = value; +} + +template <typename ValueType> +void IDBKeyTree<ValueType>::remove(IDBKey* key) +{ + TreeNode* node = m_tree.remove(key); + if (node) + delete node; +} + +} + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBKeyTree_h diff --git a/WebCore/storage/IDBObjectStore.cpp b/WebCore/storage/IDBObjectStore.cpp new file mode 100644 index 0000000..b457cd1 --- /dev/null +++ b/WebCore/storage/IDBObjectStore.cpp @@ -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. + */ + +#include "config.h" +#include "IDBObjectStore.h" + +#include "DOMStringList.h" +#include "IDBAny.h" +#include "IDBIndex.h" +#include "IDBKey.h" +#include "IDBKeyRange.h" +#include "SerializedScriptValue.h" +#include <wtf/UnusedParam.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore) + : m_objectStore(idbObjectStore) +{ + // 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) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->get(key, request); + return request; +} + +PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->put(value, key, true, request); + return request; +} + +PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->put(value, key, false, request); + return request; +} + +PassRefPtr<IDBRequest> IDBObjectStore::remove(ScriptExecutionContext* context, PassRefPtr<IDBKey> key) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->remove(key, request); + return request; +} + +PassRefPtr<IDBRequest> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const String& keyPath, bool unique) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->createIndex(name, keyPath, unique, request); + return request; +} + +PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name) +{ + RefPtr<IDBIndexBackendInterface> index = m_objectStore->index(name); + ASSERT(index); // FIXME: If this is null, we should raise a NOT_FOUND_ERR. + return IDBIndex::create(index.release()); +} + +PassRefPtr<IDBRequest> IDBObjectStore::removeIndex(ScriptExecutionContext* context, const String& name) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->removeIndex(name, request); + return request; +} + +PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction) +{ + RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this)); + m_objectStore->openCursor(range, direction, request); + return request.release(); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBObjectStore.h b/WebCore/storage/IDBObjectStore.h new file mode 100644 index 0000000..035f5d8 --- /dev/null +++ b/WebCore/storage/IDBObjectStore.h @@ -0,0 +1,82 @@ +/* + * 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 "IDBKeyRange.h" +#include "IDBObjectStoreBackendInterface.h" +#include "IDBRequest.h" +#include "PlatformString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +class DOMStringList; +class IDBAny; +class IDBIndexRequest; +class IDBKey; +class SerializedScriptValue; + +class IDBObjectStore : public RefCounted<IDBObjectStore> { +public: + static PassRefPtr<IDBObjectStore> create(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore) + { + return adoptRef(new IDBObjectStore(idbObjectStore)); + } + ~IDBObjectStore() { } + + String name() const; + String keyPath() const; + PassRefPtr<DOMStringList> indexNames() const; + + PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey> key); + PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0); + PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0); + PassRefPtr<IDBRequest> remove(ScriptExecutionContext*, PassRefPtr<IDBKey> key); + + PassRefPtr<IDBRequest> createIndex(ScriptExecutionContext*, const String& name, const String& keyPath, bool unique = false); + PassRefPtr<IDBIndex> index(const String& name); + PassRefPtr<IDBRequest> removeIndex(ScriptExecutionContext*, const String& name); + + PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT); + +private: + IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface>); + + RefPtr<IDBObjectStoreBackendInterface> m_objectStore; +}; + +} // namespace WebCore + +#endif + +#endif // IDBObjectStore_h + diff --git a/WebCore/storage/IDBObjectStore.idl b/WebCore/storage/IDBObjectStore.idl new file mode 100644 index 0000000..1649a1d --- /dev/null +++ b/WebCore/storage/IDBObjectStore.idl @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBObjectStore { + [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key); + // FIXME: Come to concensus re getAll. + // FIXME: SerializedScriptValue raises an exception if you pass in something that can't be serialized. + // We need to instead "raise" this error via an error callback. + [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key); + [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key); + [CallWith=ScriptExecutionContext] IDBRequest remove(in IDBKey key); + // FIXME: write openCursor + [CallWith=ScriptExecutionContext] IDBRequest createIndex(in DOMString name, in [ConvertNullToNullString] DOMString keyPath, in [Optional] boolean unique); + // FIXME: This needs to raise an IDBDatabaseException on errors. + IDBIndex index(in DOMString name); + [CallWith=ScriptExecutionContext] IDBRequest removeIndex(in DOMString name); + + [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction); + + readonly attribute DOMString name; + readonly attribute [ConvertNullStringTo=Null] DOMString keyPath; + readonly attribute DOMStringList indexNames; + }; +} diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp new file mode 100755 index 0000000..1b9b76b --- /dev/null +++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp @@ -0,0 +1,313 @@ +/* + * 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" + +#include "DOMStringList.h" +#include "IDBBindingUtilities.h" +#include "IDBCallbacks.h" +#include "IDBCursorBackendImpl.h" +#include "IDBDatabaseBackendImpl.h" +#include "IDBDatabaseException.h" +#include "IDBIndexBackendImpl.h" +#include "IDBKeyPath.h" +#include "IDBKeyPathBackendImpl.h" +#include "IDBKeyRange.h" +#include "SQLiteDatabase.h" +#include "SQLiteStatement.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl() +{ +} + +IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl* 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(); +} + +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::Type type) +{ + switch (type) { + case IDBKey::StringType: + return "WHERE objectStoreId = ? AND keyString = ?"; + case IDBKey::NumberType: + return "WHERE objectStoreId = ? AND keyNumber = ?"; + // FIXME: Implement date. + case IDBKey::NullType: + return "WHERE objectStoreId = ? AND keyString IS NULL AND keyDate IS NULL AND keyNumber IS NULL"; + } + + ASSERT_NOT_REACHED(); + return ""; +} + +// Returns number of items bound. +static int bindKey(SQLiteStatement& query, int column, IDBKey* key) +{ + switch (key->type()) { + case IDBKey::StringType: + query.bindText(column, key->string()); + return 1; + case IDBKey::NumberType: + query.bindInt(column, key->number()); + return 1; + // FIXME: Implement date. + case IDBKey::NullType: + return 0; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key) +{ + query.bindInt64(1, id); + bindKey(query, 2, key); +} + +void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) +{ + SQLiteStatement query(sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_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); +} + +void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks) +{ + RefPtr<SerializedScriptValue> value = prpValue; + RefPtr<IDBKey> key = prpKey; + + if (!m_keyPath.isNull()) { + if (key) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath.")); + return; + } + Vector<RefPtr<SerializedScriptValue> > values; + values.append(value); + Vector<RefPtr<IDBKey> > idbKeys; + IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, m_keyPath, idbKeys); + if (idbKeys.isEmpty()) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "An invalid keyPath was supplied for an objectStore.")); + return; + } + key = idbKeys[0]; + } + + if (!key) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied.")); + return; + } + + SQLiteStatement getQuery(sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key->type())); + bool ok = getQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(getQuery, m_id, key.get()); + bool existingValue = getQuery.step() == SQLResultRow; + if (addOnly && existingValue) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store.")); + return; + } + + String sql = existingValue ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" + : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; + SQLiteStatement putQuery(sqliteDatabase(), sql); + ok = putQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + switch (key->type()) { + case IDBKey::StringType: + putQuery.bindText(1, key->string()); + putQuery.bindNull(2); + putQuery.bindNull(3); + break; + // FIXME: Implement date. + case IDBKey::NumberType: + putQuery.bindNull(1); + putQuery.bindNull(2); + putQuery.bindInt(3, key->number()); + break; + case IDBKey::NullType: + putQuery.bindNull(1); + putQuery.bindNull(2); + putQuery.bindNull(3); + break; + default: + ASSERT_NOT_REACHED(); + } + putQuery.bindText(4, value->toWireString()); + if (existingValue) + putQuery.bindInt(5, getQuery.getColumnInt(0)); + else + putQuery.bindInt64(5, m_id); + + ok = putQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + callbacks->onSuccess(key.get()); +} + +void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) +{ + SQLiteStatement query(sqliteDatabase(), "DELETE FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_id, key.get()); + if (query.step() != SQLResultDone) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); + return; + } + + callbacks->onSuccess(); +} + +void IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks> callbacks) +{ + if (m_indexes.contains(name)) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Index name already exists.")); + return; + } + + SQLiteStatement insert(sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); + bool ok = insert.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + insert.bindInt64(1, m_id); + insert.bindText(2, name); + insert.bindText(3, keyPath); + insert.bindInt(4, static_cast<int>(unique)); + ok = insert.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + int64_t id = sqliteDatabase().lastInsertRowID(); + + RefPtr<IDBIndexBackendInterface> index = IDBIndexBackendImpl::create(this, id, name, keyPath, unique); + ASSERT(index->name() == name); + m_indexes.set(name, index); + callbacks->onSuccess(index.release()); +} + +PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name) +{ + return m_indexes.get(name); +} + +void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCallbacks> callbacks) +{ + if (!m_indexes.contains(name)) { + callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Index name does not exist.")); + return; + } + + SQLiteStatement deleteQuery(sqliteDatabase(), "DELETE FROM Indexes WHERE name = ? AND objectStoreId = ?"); + bool ok = deleteQuery.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + deleteQuery.bindText(1, name); + deleteQuery.bindInt64(2, m_id); + ok = deleteQuery.step() == SQLResultDone; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. + + // FIXME: Delete index data as well. + + m_indexes.remove(name); + callbacks->onSuccess(); +} + +void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks) +{ + // FIXME: Fully implement. + + RefPtr<IDBKey> key = range->left(); + SQLiteStatement query(sqliteDatabase(), "SELECT id, value FROM ObjectStoreData " + whereClause(key->type())); + bool ok = query.prepare() == SQLResultOk; + ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? + + bindWhereClause(query, m_id, key.get()); + if (query.step() != SQLResultRow) { + callbacks->onSuccess(); + return; + } + + RefPtr<SerializedScriptValue> value = SerializedScriptValue::createFromWire(query.getColumnText(1)); + RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(this, range, static_cast<IDBCursor::Direction>(direction), key.release(), value.release()); + 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(this, id, name, keyPath, unique)); + } +} + +SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const +{ + return m_database->sqliteDatabase(); +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.h b/WebCore/storage/IDBObjectStoreBackendImpl.h new file mode 100644 index 0000000..e1058c8 --- /dev/null +++ b/WebCore/storage/IDBObjectStoreBackendImpl.h @@ -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. + */ + +#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 SQLiteDatabase; + +class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface { +public: + static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBDatabaseBackendImpl* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement) + { + return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement)); + } + ~IDBObjectStoreBackendImpl(); + + int64_t id() const { return m_id; } + String name() const { return m_name; } + String keyPath() const { return m_keyPath; } + PassRefPtr<DOMStringList> indexNames() const; + + void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>); + void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>); + void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>); + + void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>); + PassRefPtr<IDBIndexBackendInterface> index(const String& name); + void removeIndex(const String& name, PassRefPtr<IDBCallbacks>); + + void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>); + + IDBDatabaseBackendImpl* database() const { return m_database.get(); } + +private: + IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl*, int64_t id, const String& name, const String& keyPath, bool autoIncrement); + + void loadIndexes(); + SQLiteDatabase& sqliteDatabase() const; + + RefPtr<IDBDatabaseBackendImpl> m_database; + + int64_t m_id; + String m_name; + String m_keyPath; + bool m_autoIncrement; + + typedef HashMap<String, RefPtr<IDBIndexBackendInterface> > IndexMap; + IndexMap m_indexes; +}; + +} // namespace WebCore + +#endif + +#endif // IDBObjectStoreBackendImpl_h diff --git a/WebCore/storage/IDBObjectStoreBackendInterface.h b/WebCore/storage/IDBObjectStoreBackendInterface.h new file mode 100644 index 0000000..200ac29 --- /dev/null +++ b/WebCore/storage/IDBObjectStoreBackendInterface.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBObjectStoreBackendInterface_h +#define IDBObjectStoreBackendInterface_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 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> key, PassRefPtr<IDBCallbacks>) = 0; + virtual void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>) = 0; + virtual void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0; + + virtual void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>) = 0; + virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name) = 0; + virtual void removeIndex(const String& name, PassRefPtr<IDBCallbacks>) = 0; + + virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBObjectStoreBackendInterface_h + diff --git a/WebCore/storage/IDBPendingTransactionMonitor.cpp b/WebCore/storage/IDBPendingTransactionMonitor.cpp new file mode 100644 index 0000000..d026099 --- /dev/null +++ b/WebCore/storage/IDBPendingTransactionMonitor.cpp @@ -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. + */ + +#include "config.h" +#include "IDBPendingTransactionMonitor.h" + +#if ENABLE(INDEXED_DATABASE) + +namespace WebCore { + +Vector<int>* IDBPendingTransactionMonitor::m_ids = 0; + +bool IDBPendingTransactionMonitor::hasPendingTransactions() +{ + return m_ids && m_ids->size(); +} + +void IDBPendingTransactionMonitor::addPendingTransaction(int id) +{ + if (!m_ids) + m_ids = new Vector<int>(); + m_ids->append(id); +} + +void IDBPendingTransactionMonitor::removePendingTransaction(int id) +{ + m_ids->remove(id); + if (!m_ids->size()) { + delete m_ids; + m_ids = 0; + } +} + +void IDBPendingTransactionMonitor::clearPendingTransactions() +{ + if (!m_ids) + return; + + m_ids->clear(); + delete m_ids; + m_ids = 0; +} + +const Vector<int>& IDBPendingTransactionMonitor::pendingTransactions() +{ + return *m_ids; +} + +}; +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBPendingTransactionMonitor.h b/WebCore/storage/IDBPendingTransactionMonitor.h new file mode 100644 index 0000000..00e833a --- /dev/null +++ b/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 { + +// 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 transaction IDs 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 bool hasPendingTransactions(); + static void addPendingTransaction(int id); + static void removePendingTransaction(int id); + static void clearPendingTransactions(); + static const Vector<int>& pendingTransactions(); + +private: + IDBPendingTransactionMonitor(); + + static Vector<int>* m_ids; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBPendingTransactionMonitor_h diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp index 1a20499..94ef7e5 100644 --- a/WebCore/storage/IDBRequest.cpp +++ b/WebCore/storage/IDBRequest.cpp @@ -25,40 +25,155 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #include "config.h" #include "IDBRequest.h" #if ENABLE(INDEXED_DATABASE) -#include "IDBDatabaseError.h" -#include "SerializedScriptValue.h" +#include "Event.h" +#include "EventException.h" +#include "EventListener.h" +#include "EventNames.h" +#include "IDBCursor.h" +#include "IDBDatabase.h" +#include "IDBIndex.h" +#include "IDBErrorEvent.h" +#include "IDBObjectStore.h" +#include "IDBSuccessEvent.h" +#include "ScriptExecutionContext.h" namespace WebCore { -IDBRequest::IDBRequest(ScriptExecutionContext* context) +IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source) : ActiveDOMObject(context, this) + , m_source(source) + , m_result(IDBAny::create()) + , m_timer(this, &IDBRequest::timerFired) + , m_aborted(false) + , m_readyState(INITIAL) { } IDBRequest::~IDBRequest() { + if (m_readyState != DONE) + abort(); +} + +void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error) +{ + onEventCommon(); + m_error = error; +} + +void IDBRequest::onSuccess() +{ + onEventCommon(); + m_result->set(); +} + +void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend) +{ + onEventCommon(); + m_result->set(IDBCursor::create(backend)); +} + +void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend) +{ + onEventCommon(); + m_result->set(IDBDatabase::create(backend)); +} + +void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend) +{ + onEventCommon(); + m_result->set(IDBIndex::create(backend)); +} + +void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey) +{ + onEventCommon(); + m_result->set(idbKey); +} + +void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend) +{ + onEventCommon(); + m_result->set(IDBObjectStore::create(backend)); +} + +void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue) +{ + onEventCommon(); + m_result->set(serializedScriptValue); } void IDBRequest::abort() { + m_timer.stop(); + m_aborted = true; + // FIXME: This should cancel any pending work being done in the backend. +} + +ScriptExecutionContext* IDBRequest::scriptExecutionContext() const +{ + return ActiveDOMObject::scriptExecutionContext(); +} + +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 0; + return &m_eventTargetData; } EventTargetData* IDBRequest::ensureEventTargetData() { - return 0; + return &m_eventTargetData; } -} // namespace WebCore +void IDBRequest::timerFired(Timer<IDBRequest>*) +{ + ASSERT(m_readyState == DONE); + ASSERT(m_selfRef); + ASSERT(!m_aborted); + + // We need to keep self-referencing ourself, otherwise it's possible we'll be deleted. + // But in some cases, suspend() could be called while we're dispatching an event, so we + // need to make sure that resume() doesn't re-start the timer based on m_selfRef being set. + RefPtr<IDBRequest> selfRef = m_selfRef.release(); + + if (m_error) { + ASSERT(m_result->type() == IDBAny::UndefinedType); + dispatchEvent(IDBErrorEvent::create(m_source, *m_error)); + } else { + ASSERT(m_result->type() != IDBAny::UndefinedType); + dispatchEvent(IDBSuccessEvent::create(m_source, m_result)); + } +} + +void IDBRequest::onEventCommon() +{ + ASSERT(m_readyState < DONE); + ASSERT(m_result->type() == IDBAny::UndefinedType); + ASSERT(!m_error); + ASSERT(!m_selfRef); + ASSERT(!m_timer.isActive()); + + if (m_aborted) + return; -#endif // ENABLE(INDEXED_DATABASE) + m_readyState = DONE; + m_selfRef = this; + m_timer.startOneShot(0); +} + +} // namespace WebCore +#endif diff --git a/WebCore/storage/IDBRequest.h b/WebCore/storage/IDBRequest.h index 5f00aa8..ddfdcf3 100644 --- a/WebCore/storage/IDBRequest.h +++ b/WebCore/storage/IDBRequest.h @@ -25,64 +25,88 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef IDBRequest_h #define IDBRequest_h +#if ENABLE(INDEXED_DATABASE) + #include "ActiveDOMObject.h" +#include "EventListener.h" +#include "EventNames.h" #include "EventTarget.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> - -#if ENABLE(INDEXED_DATABASE) +#include "IDBAny.h" +#include "IDBCallbacks.h" +#include "Timer.h" namespace WebCore { -class IDBDatabaseError; -class SerializedScriptValue; - -class IDBRequest : public RefCounted<IDBRequest>, public ActiveDOMObject, public EventTarget { +class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject { public: - static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context) - { - return adoptRef(new IDBRequest(context)); - } - ~IDBRequest(); + static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source) { return adoptRef(new IDBRequest(context, source)); } + virtual ~IDBRequest(); + // Defined in the IDL void abort(); + enum ReadyState { + INITIAL = 0, + LOADING = 1, + DONE = 2 + }; unsigned short readyState() const { return m_readyState; } - IDBDatabaseError* error() const { return m_error.get(); } - SerializedScriptValue* result() const { return m_result.get(); } - + PassRefPtr<IDBDatabaseError> error() const { return m_error; } + PassRefPtr<IDBAny> result() { return m_result; } DEFINE_ATTRIBUTE_EVENT_LISTENER(success); DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - using RefCounted<IDBRequest>::ref; - using RefCounted<IDBRequest>::deref; - - // EventTarget interface - virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); } + // 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<SerializedScriptValue>); + + // EventTarget virtual IDBRequest* toIDBRequest() { return this; } + // ActiveDOMObject + virtual ScriptExecutionContext* scriptExecutionContext() const; + virtual bool canSuspend() const; + + using RefCounted<IDBCallbacks>::ref; + using RefCounted<IDBCallbacks>::deref; + private: - explicit IDBRequest(ScriptExecutionContext* context); + IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source); + + void timerFired(Timer<IDBRequest>*); + void onEventCommon(); - // EventTarget interface + // EventTarget virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } virtual EventTargetData* eventTargetData(); virtual EventTargetData* ensureEventTargetData(); - unsigned short m_readyState; + RefPtr<IDBAny> m_source; + + RefPtr<IDBAny> m_result; RefPtr<IDBDatabaseError> m_error; - RefPtr<SerializedScriptValue> m_result; + // Used to fire events asynchronously. + Timer<IDBRequest> m_timer; + RefPtr<IDBRequest> m_selfRef; // This is set to us iff there's an event pending. + + bool m_aborted; + ReadyState m_readyState; EventTargetData m_eventTargetData; }; } // namespace WebCore -#endif +#endif // ENABLE(INDEXED_DATABASE) #endif // IDBRequest_h - diff --git a/WebCore/storage/IDBRequest.idl b/WebCore/storage/IDBRequest.idl index b34184c..9d7e0e4 100644 --- a/WebCore/storage/IDBRequest.idl +++ b/WebCore/storage/IDBRequest.idl @@ -25,6 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + module storage { interface [ @@ -32,14 +33,29 @@ module storage { EventTarget ] IDBRequest { void abort(); + + // States const unsigned short INITIAL = 0; const unsigned short LOADING = 1; const unsigned short DONE = 2; readonly attribute unsigned short readyState; + + // Possible results readonly attribute IDBDatabaseError error; - readonly attribute [CustomGetter] any result; + readonly attribute IDBAny result; + + // Events attribute EventListener onsuccess; attribute EventListener onerror; - }; + // EventTarget interface + void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + boolean dispatchEvent(in Event evt) + raises(EventException); + }; } diff --git a/WebCore/storage/IDBSuccessEvent.cpp b/WebCore/storage/IDBSuccessEvent.cpp new file mode 100644 index 0000000..2dcd964 --- /dev/null +++ b/WebCore/storage/IDBSuccessEvent.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBSuccessEvent.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "EventNames.h" +#include "IDBAny.h" + +namespace WebCore { + +PassRefPtr<IDBSuccessEvent> IDBSuccessEvent::create(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result) +{ + return adoptRef(new IDBSuccessEvent(source, result)); +} + +IDBSuccessEvent::IDBSuccessEvent(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result) + : IDBEvent(eventNames().successEvent, source) + , m_result(result) +{ +} + +IDBSuccessEvent::~IDBSuccessEvent() +{ +} + +PassRefPtr<IDBAny> IDBSuccessEvent::result() +{ + return m_result; +} + +} // namespace WebCore + +#endif diff --git a/WebCore/storage/IDBSuccessEvent.h b/WebCore/storage/IDBSuccessEvent.h new file mode 100644 index 0000000..5be660a --- /dev/null +++ b/WebCore/storage/IDBSuccessEvent.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDBSuccessEvent_h +#define IDBSuccessEvent_h + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBEvent.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBAny; + +class IDBSuccessEvent : public IDBEvent { +public: + static PassRefPtr<IDBSuccessEvent> create(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result); + // FIXME: Need to allow creation of these events from JS. + virtual ~IDBSuccessEvent(); + + PassRefPtr<IDBAny> result(); + + virtual bool isIDBSuccessEvent() const { return true; } + +private: + IDBSuccessEvent(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result); + + RefPtr<IDBAny> m_result; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBEvent_h diff --git a/WebCore/storage/IDBSuccessEvent.idl b/WebCore/storage/IDBSuccessEvent.idl new file mode 100644 index 0000000..b4ea7d2 --- /dev/null +++ b/WebCore/storage/IDBSuccessEvent.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=INDEXED_DATABASE + ] IDBSuccessEvent : IDBEvent { + readonly attribute IDBAny result; + }; +} diff --git a/WebCore/storage/IDBTransaction.cpp b/WebCore/storage/IDBTransaction.cpp new file mode 100644 index 0000000..4e93378 --- /dev/null +++ b/WebCore/storage/IDBTransaction.cpp @@ -0,0 +1,135 @@ +/* + * 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 "IDBDatabase.h" +#include "IDBObjectStore.h" +#include "IDBObjectStoreBackendInterface.h" +#include "IDBPendingTransactionMonitor.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_stopped(false) + , m_timer(this, &IDBTransaction::timerFired) +{ + IDBPendingTransactionMonitor::addPendingTransaction(m_backend->id()); +} + +IDBTransaction::~IDBTransaction() +{ +} + +unsigned short IDBTransaction::mode() const +{ + return m_backend->mode(); +} + +IDBDatabase* IDBTransaction::db() +{ + return m_database.get(); +} + +PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, const ExceptionCode&) +{ + RefPtr<IDBObjectStoreBackendInterface> objectStoreBackend = m_backend->objectStore(name); + RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend); + return objectStore.release(); +} + +void IDBTransaction::abort() +{ + m_backend->abort(); +} + +ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const +{ + return ActiveDOMObject::scriptExecutionContext(); +} + +void IDBTransaction::onAbort() +{ + if (!m_stopped) { + m_selfRef = this; + m_stopped = true; + m_timer.startOneShot(0); + } + // Release the backend as it holds a (circular) reference back to us. + m_backend.clear(); +} + +int IDBTransaction::id() const +{ + return m_backend->id(); +} + +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_stopped) { + // The document is getting detached. Abort! + m_stopped = true; + m_backend->abort(); + } +} + +EventTargetData* IDBTransaction::eventTargetData() +{ + return &m_eventTargetData; +} + +EventTargetData* IDBTransaction::ensureEventTargetData() +{ + return &m_eventTargetData; +} + +void IDBTransaction::timerFired(Timer<IDBTransaction>* transaction) +{ + ASSERT(m_selfRef); + + RefPtr<IDBTransaction> selfRef = m_selfRef.release(); + dispatchEvent(IDBAbortEvent::create()); +} + +} + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransaction.h b/WebCore/storage/IDBTransaction.h new file mode 100644 index 0000000..3c7f9dd --- /dev/null +++ b/WebCore/storage/IDBTransaction.h @@ -0,0 +1,108 @@ +/* + * 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, + SNAPSHOT_READ = 2 + }; + + unsigned short mode() const; + IDBDatabase* db(); + PassRefPtr<IDBObjectStore> objectStore(const String& name, const ExceptionCode&); + void abort(); + + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); + DEFINE_ATTRIBUTE_EVENT_LISTENER(timeout); + + // IDBTransactionCallbacks + virtual void onAbort(); + virtual int id() const; + + // 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 timerFired(Timer<IDBTransaction>*); + + EventTargetData m_eventTargetData; + RefPtr<IDBTransactionBackendInterface> m_backend; + RefPtr<IDBDatabase> m_database; + + bool m_stopped; + Timer<IDBTransaction> m_timer; + 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/WebCore/storage/IDBTransaction.idl b/WebCore/storage/IDBTransaction.idl new file mode 100644 index 0000000..a3907dc --- /dev/null +++ b/WebCore/storage/IDBTransaction.idl @@ -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. + * + * 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 SNAPSHOT_READ = 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/WebCore/storage/IDBTransactionBackendImpl.cpp b/WebCore/storage/IDBTransactionBackendImpl.cpp new file mode 100755 index 0000000..51b33b2 --- /dev/null +++ b/WebCore/storage/IDBTransactionBackendImpl.cpp @@ -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. + * + * 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 "SQLiteDatabase.h" + +namespace WebCore { + +PassRefPtr<IDBTransactionBackendInterface> IDBTransactionBackendImpl::create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl* database) +{ + return adoptRef(new IDBTransactionBackendImpl(objectStores, mode, timeout, id, database)); +} + +IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl* database) + : m_objectStoreNames(objectStores) + , m_mode(mode) + , m_timeout(timeout) + , m_id(id) + , m_aborted(false) + , m_database(database) +{ +} + +PassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStore(const String& name) +{ + return m_database->objectStore(name, 0); // FIXME: remove mode param. +} + +void IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>) +{ + // FIXME: implement. + ASSERT_NOT_REACHED(); +} + +void IDBTransactionBackendImpl::abort() +{ + m_aborted = true; + m_callbacks->onAbort(); +} + +}; + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransactionBackendImpl.h b/WebCore/storage/IDBTransactionBackendImpl.h new file mode 100755 index 0000000..fb57401 --- /dev/null +++ b/WebCore/storage/IDBTransactionBackendImpl.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 IDBTransactionBackendImpl_h +#define IDBTransactionBackendImpl_h + +#if ENABLE(INDEXED_DATABASE) + +#include "DOMStringList.h" +#include "IDBTransactionBackendInterface.h" +#include "IDBTransactionCallbacks.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +class IDBDatabaseBackendImpl; + +class IDBTransactionBackendImpl : public IDBTransactionBackendInterface { +public: + static PassRefPtr<IDBTransactionBackendInterface> create(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl*); + virtual ~IDBTransactionBackendImpl() { } + + virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name); + virtual unsigned short mode() const { return m_mode; } + virtual void scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>); + virtual void abort(); + virtual int id() const { return m_id; } + virtual void setCallbacks(IDBTransactionCallbacks* callbacks) { m_callbacks = callbacks; } + +private: + IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl*); + + RefPtr<DOMStringList> m_objectStoreNames; + unsigned short m_mode; + unsigned long m_timeout; + int m_id; + bool m_aborted; + RefPtr<IDBTransactionCallbacks> m_callbacks; + RefPtr<IDBDatabaseBackendImpl> m_database; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBTransactionBackendImpl_h diff --git a/WebCore/storage/IDBTransactionBackendInterface.h b/WebCore/storage/IDBTransactionBackendInterface.h new file mode 100644 index 0000000..39651f1 --- /dev/null +++ b/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) = 0; + virtual unsigned short mode() const = 0; + virtual void scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>) = 0; + virtual void abort() = 0; + virtual int id() const = 0; + virtual void setCallbacks(IDBTransactionCallbacks*) = 0; +}; + +} // namespace WebCore + +#endif + +#endif // IDBTransactionBackendInterface_h + diff --git a/WebCore/storage/IDBTransactionCallbacks.h b/WebCore/storage/IDBTransactionCallbacks.h new file mode 100644 index 0000000..38181fc --- /dev/null +++ b/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 int id() const = 0; + // FIXME: add the rest +}; + +} // namespace WebCore + +#endif + +#endif // IDBTransactionCallbacks_h diff --git a/WebCore/storage/IDBTransactionCoordinator.cpp b/WebCore/storage/IDBTransactionCoordinator.cpp new file mode 100644 index 0000000..9790c1f --- /dev/null +++ b/WebCore/storage/IDBTransactionCoordinator.cpp @@ -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. + */ + +#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 { + +IDBTransactionCoordinator::IDBTransactionCoordinator() + : m_nextID(0) +{ +} + +IDBTransactionCoordinator::~IDBTransactionCoordinator() +{ +} + +PassRefPtr<IDBTransactionBackendInterface> IDBTransactionCoordinator::createTransaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl* database) +{ + RefPtr<IDBTransactionBackendInterface> transaction = IDBTransactionBackendImpl::create(objectStores, mode, timeout, ++m_nextID, database); + m_transactionQueue.add(transaction.get()); + m_idMap.add(m_nextID, transaction); + return transaction.release(); +} + +void IDBTransactionCoordinator::abort(int id) +{ + ASSERT(m_idMap.contains(id)); + RefPtr<IDBTransactionBackendInterface> transaction = m_idMap.get(id); + ASSERT(transaction); + m_transactionQueue.remove(transaction.get()); + m_idMap.remove(id); + transaction->abort(); + // FIXME: this will change once we have transactions actually running. +} + +}; + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/WebCore/storage/IDBTransactionCoordinator.h b/WebCore/storage/IDBTransactionCoordinator.h new file mode 100644 index 0000000..104a956 --- /dev/null +++ b/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 IDBTransactionCallbacks; +class IDBDatabaseBackendImpl; + +// This class manages transactions as follows. Requests for new transactions are +// always satisfied and the new transaction is placed in a queue. +// Transactions are not actually started until the first operation is issued. +// Each transaction executes in a separate thread and is committed automatically +// when there are no more operations issued in its context. +// When starting, a transaction will attempt to lock all the object stores in its +// scope. If this does not happen within a given timeout, an exception is raised. +// The Coordinator maintains a pool of threads. If there are no threads available +// the next transaction in the queue will have to wait until a thread becomes +// available. +// Transactions are executed in the order the were created. +class IDBTransactionCoordinator : public RefCounted<IDBTransactionCoordinator> { +public: + static PassRefPtr<IDBTransactionCoordinator> create() { return adoptRef(new IDBTransactionCoordinator()); } + virtual ~IDBTransactionCoordinator(); + + PassRefPtr<IDBTransactionBackendInterface> createTransaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, IDBDatabaseBackendImpl*); + void abort(int transactionId); + +private: + IDBTransactionCoordinator(); + + ListHashSet<IDBTransactionBackendInterface*> m_transactionQueue; + typedef HashMap<int, RefPtr<IDBTransactionBackendInterface> > IdToTransactionMap; + IdToTransactionMap m_idMap; + int m_nextID; +}; + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) + +#endif // IDBTransactionCoordinator_h diff --git a/WebCore/storage/LocalStorageTask.cpp b/WebCore/storage/LocalStorageTask.cpp index 12cc083..d31c991 100644 --- a/WebCore/storage/LocalStorageTask.cpp +++ b/WebCore/storage/LocalStorageTask.cpp @@ -39,7 +39,7 @@ LocalStorageTask::LocalStorageTask(Type type, StorageAreaSync* area) , m_thread(0) { ASSERT(m_area); - ASSERT(m_type == AreaImport || m_type == AreaSync); + ASSERT(m_type == AreaImport || m_type == AreaSync || m_type == DeleteEmptyDatabase); } LocalStorageTask::LocalStorageTask(Type type, LocalStorageThread* thread) @@ -64,6 +64,9 @@ void LocalStorageTask::performTask() case AreaSync: m_area->performSync(); break; + case DeleteEmptyDatabase: + m_area->deleteEmptyDatabase(); + break; case TerminateThread: m_thread->performTerminate(); break; diff --git a/WebCore/storage/LocalStorageTask.h b/WebCore/storage/LocalStorageTask.h index dc3e7e2..a2e35ea 100644 --- a/WebCore/storage/LocalStorageTask.h +++ b/WebCore/storage/LocalStorageTask.h @@ -39,13 +39,14 @@ namespace WebCore { // FIXME: Rename this class to StorageTask class LocalStorageTask : public Noncopyable { public: - enum Type { AreaImport, AreaSync, TerminateThread }; + enum Type { AreaImport, AreaSync, DeleteEmptyDatabase, TerminateThread }; ~LocalStorageTask(); - static PassOwnPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return new LocalStorageTask(AreaImport, area); } - static PassOwnPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return new LocalStorageTask(AreaSync, area); } - static PassOwnPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return new LocalStorageTask(TerminateThread, thread); } + 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(); diff --git a/WebCore/storage/LocalStorageThread.cpp b/WebCore/storage/LocalStorageThread.cpp index d4a7b4c..cbb81c5 100644 --- a/WebCore/storage/LocalStorageThread.cpp +++ b/WebCore/storage/LocalStorageThread.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassOwnPtr<LocalStorageThread> LocalStorageThread::create() { - return new LocalStorageThread; + return adoptPtr(new LocalStorageThread); } LocalStorageThread::LocalStorageThread() diff --git a/WebCore/storage/Metadata.h b/WebCore/storage/Metadata.h new file mode 100644 index 0000000..0b06f90 --- /dev/null +++ b/WebCore/storage/Metadata.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: + * + * * 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 Metadata_h +#define Metadata_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Metadata : public RefCounted<Metadata> { +public: + static PassRefPtr<Metadata> create(double modificationTime) + { + return adoptRef(new Metadata(modificationTime)); + } + double modificationTime() const { return m_modificationTime; } + +private: + Metadata(double modificationTime) + : m_modificationTime(modificationTime) + { + } + + double m_modificationTime; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // Metadata_h diff --git a/WebCore/storage/Metadata.idl b/WebCore/storage/Metadata.idl new file mode 100644 index 0000000..711fae8 --- /dev/null +++ b/WebCore/storage/Metadata.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: + * + * * 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=FILE_SYSTEM + ] Metadata { + readonly attribute double modificationTime; + }; +} diff --git a/WebCore/storage/MetadataCallback.h b/WebCore/storage/MetadataCallback.h new file mode 100644 index 0000000..3d57400 --- /dev/null +++ b/WebCore/storage/MetadataCallback.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 MetadataCallback_h +#define MetadataCallback_h + +#if ENABLE(FILE_SYSTEM) + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Metadata; +class ScriptExecutionContext; + +class MetadataCallback : public RefCounted<MetadataCallback> { +public: + virtual ~MetadataCallback() { } + virtual bool handleEvent(Metadata*) = 0; +}; + +} // namespace + +#endif // ENABLE(FILE_SYSTEM) + +#endif // MetadataCallback_h diff --git a/WebCore/storage/MetadataCallback.idl b/WebCore/storage/MetadataCallback.idl new file mode 100644 index 0000000..44ca180 --- /dev/null +++ b/WebCore/storage/MetadataCallback.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=FILE_SYSTEM, + Callback + ] MetadataCallback { + boolean handleEvent(in Metadata metadata); + }; +} diff --git a/WebCore/storage/OriginQuotaManager.cpp b/WebCore/storage/OriginQuotaManager.cpp index 30b3271..0f415c1 100644 --- a/WebCore/storage/OriginQuotaManager.cpp +++ b/WebCore/storage/OriginQuotaManager.cpp @@ -30,7 +30,7 @@ #if ENABLE(DATABASE) -#include "Database.h" +#include "AbstractDatabase.h" #include "OriginUsageRecord.h" namespace WebCore { @@ -42,6 +42,18 @@ OriginQuotaManager::OriginQuotaManager() { } +bool OriginQuotaManager::tryLock() +{ + bool locked = m_usageRecordGuard.tryLock(); +#ifndef NDEBUG + if (locked) + m_usageRecordGuardLocked = true; + else + ASSERT(m_usageRecordGuardLocked); +#endif + return locked; +} + void OriginQuotaManager::lock() { m_usageRecordGuard.lock(); @@ -63,7 +75,7 @@ void OriginQuotaManager::trackOrigin(PassRefPtr<SecurityOrigin> origin) ASSERT(m_usageRecordGuardLocked); ASSERT(!m_usageMap.contains(origin.get())); - m_usageMap.set(origin, new OriginUsageRecord); + m_usageMap.set(origin->threadsafeCopy(), new OriginUsageRecord); } bool OriginQuotaManager::tracksOrigin(SecurityOrigin* origin) const @@ -100,7 +112,7 @@ void OriginQuotaManager::removeOrigin(SecurityOrigin* origin) } } -void OriginQuotaManager::markDatabase(Database* database) +void OriginQuotaManager::markDatabase(AbstractDatabase* database) { ASSERT(database); ASSERT(m_usageRecordGuardLocked); diff --git a/WebCore/storage/OriginQuotaManager.h b/WebCore/storage/OriginQuotaManager.h index 2e3615d..ec9620c 100644 --- a/WebCore/storage/OriginQuotaManager.h +++ b/WebCore/storage/OriginQuotaManager.h @@ -31,20 +31,21 @@ #if ENABLE(DATABASE) -#include "StringHash.h" #include "SecurityOriginHash.h" #include <wtf/HashMap.h> #include <wtf/Threading.h> +#include <wtf/text/StringHash.h> namespace WebCore { -class Database; +class AbstractDatabase; class OriginUsageRecord; class OriginQuotaManager : public Noncopyable { public: OriginQuotaManager(); + bool tryLock(); void lock(); void unlock(); @@ -54,7 +55,7 @@ public: void removeDatabase(SecurityOrigin*, const String& databaseIdentifier); void removeOrigin(SecurityOrigin*); - void markDatabase(Database*); // Mark dirtiness of a specific database. + void markDatabase(AbstractDatabase*); // Mark dirtiness of a specific database. unsigned long long diskUsage(SecurityOrigin*) const; private: diff --git a/WebCore/storage/OriginUsageRecord.cpp b/WebCore/storage/OriginUsageRecord.cpp index 684df53..eac08fd 100644 --- a/WebCore/storage/OriginUsageRecord.cpp +++ b/WebCore/storage/OriginUsageRecord.cpp @@ -42,8 +42,8 @@ OriginUsageRecord::OriginUsageRecord() void OriginUsageRecord::addDatabase(const String& identifier, const String& fullPath) { ASSERT(!m_databaseMap.contains(identifier)); - ASSERT_ARG(identifier, identifier.impl()->refCount() == 1); - ASSERT_ARG(fullPath, fullPath.impl()->refCount() == 1); + ASSERT_ARG(identifier, identifier.impl()->hasOneRef() || identifier.isEmpty()); + ASSERT_ARG(fullPath, fullPath.impl()->hasOneRef() || fullPath.isEmpty()); m_databaseMap.set(identifier, DatabaseEntry(fullPath)); m_unknownSet.add(identifier); @@ -63,7 +63,7 @@ void OriginUsageRecord::removeDatabase(const String& identifier) void OriginUsageRecord::markDatabase(const String& identifier) { ASSERT(m_databaseMap.contains(identifier)); - ASSERT_ARG(identifier, identifier.impl()->refCount() == 1); + ASSERT_ARG(identifier, identifier.impl()->hasOneRef() || identifier.isEmpty()); m_unknownSet.add(identifier); m_cachedDiskUsageIsValid = false; diff --git a/WebCore/storage/OriginUsageRecord.h b/WebCore/storage/OriginUsageRecord.h index 25bddf2..a830e68 100644 --- a/WebCore/storage/OriginUsageRecord.h +++ b/WebCore/storage/OriginUsageRecord.h @@ -31,10 +31,9 @@ #if ENABLE(DATABASE) #include "PlatformString.h" -#include "StringHash.h" - #include <wtf/HashMap.h> -#include <wtf/HashSet.h> +#include <wtf/HashSet.h> +#include <wtf/text/StringHash.h> namespace WebCore { diff --git a/WebCore/storage/SQLError.h b/WebCore/storage/SQLError.h index 4414e6b..496145a 100644 --- a/WebCore/storage/SQLError.h +++ b/WebCore/storage/SQLError.h @@ -32,7 +32,7 @@ #if ENABLE(DATABASE) #include "PlatformString.h" -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { @@ -43,6 +43,17 @@ public: unsigned code() const { return m_code; } String message() const { return m_message.threadsafeCopy(); } + enum SQLErrorCode { + UNKNOWN_ERR = 0, + DATABASE_ERR = 1, + VERSION_ERR = 2, + TOO_LARGE_ERR = 3, + QUOTA_ERR = 4, + SYNTAX_ERR = 5, + CONSTRAINT_ERR = 6, + TIMEOUT_ERR = 7 + }; + private: SQLError(unsigned code, const String& message) : m_code(code), m_message(message.threadsafeCopy()) { } unsigned m_code; diff --git a/WebCore/storage/SQLError.idl b/WebCore/storage/SQLError.idl index 503fe6f..87be8c7 100644 --- a/WebCore/storage/SQLError.idl +++ b/WebCore/storage/SQLError.idl @@ -30,9 +30,20 @@ module storage { interface [ Conditional=DATABASE, - OmitConstructor + OmitConstructor, + NoStaticTables ] SQLError { readonly attribute unsigned long code; readonly attribute DOMString message; + + // SQLErrorCode: used only in the async DB API + const unsigned short UNKNOWN_ERR = 0; + const unsigned short DATABASE_ERR = 1; + const unsigned short VERSION_ERR = 2; + const unsigned short TOO_LARGE_ERR = 3; + const unsigned short QUOTA_ERR = 4; + const unsigned short SYNTAX_ERR = 5; + const unsigned short CONSTRAINT_ERR = 6; + const unsigned short TIMEOUT_ERR = 7; }; } diff --git a/WebCore/storage/SQLException.h b/WebCore/storage/SQLException.h new file mode 100644 index 0000000..a0f118d --- /dev/null +++ b/WebCore/storage/SQLException.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLException_h +#define SQLException_h + +#if ENABLE(DATABASE) + +#include "ExceptionBase.h" + +namespace WebCore { + +class SQLException : public ExceptionBase { +public: + static PassRefPtr<SQLException> create(const ExceptionCodeDescription& description) + { + return adoptRef(new SQLException(description)); + } + + static const int SQLExceptionOffset = 1000; + static const int SQLExceptionMax = 1099; + + enum SQLExceptionCode { + UNKNOWN_ERR = SQLExceptionOffset, + DATABASE_ERR = SQLExceptionOffset + 1, + VERSION_ERR = SQLExceptionOffset + 2, + TOO_LARGE_ERR = SQLExceptionOffset + 3, + QUOTA_ERR = SQLExceptionOffset + 4, + SYNTAX_ERR = SQLExceptionOffset + 5, + CONSTRAINT_ERR = SQLExceptionOffset + 6, + TIMEOUT_ERR = SQLExceptionOffset + 7 + }; + +private: + SQLException(const ExceptionCodeDescription& description) + : ExceptionBase(description) + { + } +}; + +} // namespace WebCore + +#endif // ENABLE(DATABASE) + +#endif // SQLException_h diff --git a/WebCore/storage/SQLException.idl b/WebCore/storage/SQLException.idl new file mode 100644 index 0000000..cbbc311 --- /dev/null +++ b/WebCore/storage/SQLException.idl @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=DATABASE, + NoStaticTables, + DontCheckEnums + ] SQLException { + readonly attribute unsigned long code; + readonly attribute DOMString message; + + // SQLExceptionCode: used only in the sync DB API + const unsigned short UNKNOWN_ERR = 0; + const unsigned short DATABASE_ERR = 1; + const unsigned short VERSION_ERR = 2; + const unsigned short TOO_LARGE_ERR = 3; + const unsigned short QUOTA_ERR = 4; + const unsigned short SYNTAX_ERR = 5; + const unsigned short CONSTRAINT_ERR = 6; + const unsigned short TIMEOUT_ERR = 7; + }; +} diff --git a/WebCore/storage/SQLResultSet.cpp b/WebCore/storage/SQLResultSet.cpp index 19c66c7..7482628 100644 --- a/WebCore/storage/SQLResultSet.cpp +++ b/WebCore/storage/SQLResultSet.cpp @@ -31,9 +31,6 @@ #if ENABLE(DATABASE) -#include "ExceptionCode.h" -#include "SQLValue.h" - namespace WebCore { static unsigned const MaxErrorCode = 2; diff --git a/WebCore/storage/SQLResultSet.h b/WebCore/storage/SQLResultSet.h index 5a0ff78..268472f 100644 --- a/WebCore/storage/SQLResultSet.h +++ b/WebCore/storage/SQLResultSet.h @@ -31,13 +31,12 @@ #if ENABLE(DATABASE) +#include "ExceptionCode.h" #include "SQLResultSetRowList.h" -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { -typedef int ExceptionCode; - class SQLResultSet : public ThreadSafeShared<SQLResultSet> { public: static PassRefPtr<SQLResultSet> create() { return adoptRef(new SQLResultSet); } diff --git a/WebCore/storage/SQLResultSet.idl b/WebCore/storage/SQLResultSet.idl index c98fff6..52f06da 100644 --- a/WebCore/storage/SQLResultSet.idl +++ b/WebCore/storage/SQLResultSet.idl @@ -30,12 +30,19 @@ module storage { interface [ Conditional=DATABASE, - OmitConstructor + OmitConstructor, + NoStaticTables ] SQLResultSet { readonly attribute SQLResultSetRowList rows; +#if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP readonly attribute long insertId getter raises(DOMException); +#else + // Explicitely choose 'long long' here to avoid a 64bit->32bit shortening warning for us. + readonly attribute long long insertId + getter raises(DOMException); +#endif readonly attribute long rowsAffected; }; } diff --git a/WebCore/storage/SQLResultSetRowList.idl b/WebCore/storage/SQLResultSetRowList.idl index 7ae7a9c..26239cb 100644 --- a/WebCore/storage/SQLResultSetRowList.idl +++ b/WebCore/storage/SQLResultSetRowList.idl @@ -30,7 +30,8 @@ module storage { interface [ Conditional=DATABASE, - OmitConstructor + OmitConstructor, + NoStaticTables ] SQLResultSetRowList { readonly attribute unsigned long length; [Custom] DOMObject item(in unsigned long index); diff --git a/WebCore/storage/SQLStatement.cpp b/WebCore/storage/SQLStatement.cpp index b4eb9ef..19e9e38 100644 --- a/WebCore/storage/SQLStatement.cpp +++ b/WebCore/storage/SQLStatement.cpp @@ -31,16 +31,15 @@ #if ENABLE(DATABASE) #include "Database.h" -#include "DatabaseAuthorizer.h" #include "Logging.h" #include "SQLError.h" #include "SQLiteDatabase.h" #include "SQLiteStatement.h" -#include "SQLResultSet.h" #include "SQLStatementCallback.h" #include "SQLStatementErrorCallback.h" #include "SQLTransaction.h" #include "SQLValue.h" +#include <wtf/text/CString.h> namespace WebCore { @@ -73,14 +72,14 @@ bool SQLStatement::execute(Database* db) if (m_readOnly) db->setAuthorizerReadOnly(); - SQLiteDatabase* database = &db->m_sqliteDatabase; + SQLiteDatabase* database = &db->sqliteDatabase(); SQLiteStatement statement(*database, m_statement); int result = statement.prepare(); if (result != SQLResultOk) { LOG(StorageAPI, "Unable to verify correctness of statement %s - error %i (%s)", m_statement.ascii().data(), result, database->lastErrorMsg()); - m_error = SQLError::create(1, database->lastErrorMsg()); + m_error = SQLError::create(result == SQLResultInterrupt ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, database->lastErrorMsg()); return false; } @@ -88,7 +87,7 @@ bool SQLStatement::execute(Database* db) // If this is the case, they might be trying to do something fishy or malicious if (statement.bindParameterCount() != m_arguments.size()) { LOG(StorageAPI, "Bind parameter count doesn't match number of question marks"); - m_error = SQLError::create(1, "number of '?'s in statement string does not match argument count"); + m_error = SQLError::create(db->isInterrupted() ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count"); return false; } @@ -101,7 +100,7 @@ bool SQLStatement::execute(Database* db) if (result != SQLResultOk) { LOG(StorageAPI, "Failed to bind value index %i to statement for query '%s'", i + 1, m_statement.ascii().data()); - m_error = SQLError::create(1, database->lastErrorMsg()); + m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg()); return false; } } @@ -125,19 +124,19 @@ bool SQLStatement::execute(Database* db) } while (result == SQLResultRow); if (result != SQLResultDone) { - m_error = SQLError::create(1, database->lastErrorMsg()); + m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg()); return false; } } else if (result == SQLResultDone) { // Didn't find anything, or was an insert - if (db->m_databaseAuthorizer->lastActionWasInsert()) + if (db->lastActionWasInsert()) resultSet->setInsertId(database->lastInsertRowID()); } else if (result == SQLResultFull) { // Return the Quota error - the delegate will be asked for more space and this statement might be re-run setFailureDueToQuota(); return false; } else { - m_error = SQLError::create(1, database->lastErrorMsg()); + m_error = SQLError::create(SQLError::DATABASE_ERR, database->lastErrorMsg()); return false; } @@ -153,13 +152,13 @@ bool SQLStatement::execute(Database* db) void SQLStatement::setDatabaseDeletedError() { ASSERT(!m_error && !m_resultSet); - m_error = SQLError::create(0, "unable to execute statement, because the user deleted the database"); + m_error = SQLError::create(SQLError::UNKNOWN_ERR, "unable to execute statement, because the user deleted the database"); } void SQLStatement::setVersionMismatchedError() { ASSERT(!m_error && !m_resultSet); - m_error = SQLError::create(2, "current version of the database and `oldVersion` argument do not match"); + m_error = SQLError::create(SQLError::VERSION_ERR, "current version of the database and `oldVersion` argument do not match"); } bool SQLStatement::performCallback(SQLTransaction* transaction) @@ -174,7 +173,7 @@ bool SQLStatement::performCallback(SQLTransaction* transaction) ASSERT(m_statementErrorCallback); callbackError = m_statementErrorCallback->handleEvent(transaction, m_error.get()); } else if (m_statementCallback) - m_statementCallback->handleEvent(transaction, m_resultSet.get(), callbackError); + callbackError = !m_statementCallback->handleEvent(transaction, m_resultSet.get()); // Now release our callbacks, to break reference cycles. m_statementCallback = 0; @@ -186,7 +185,7 @@ bool SQLStatement::performCallback(SQLTransaction* transaction) void SQLStatement::setFailureDueToQuota() { ASSERT(!m_error && !m_resultSet); - m_error = SQLError::create(4, "there was not enough remaining storage space, or the storage quota was reached and the user declined to allow more space"); + m_error = SQLError::create(SQLError::QUOTA_ERR, "there was not enough remaining storage space, or the storage quota was reached and the user declined to allow more space"); } void SQLStatement::clearFailureDueToQuota() @@ -197,7 +196,7 @@ void SQLStatement::clearFailureDueToQuota() bool SQLStatement::lastExecutionFailedDueToQuota() const { - return m_error && m_error->code() == 4; + return m_error && m_error->code() == SQLError::QUOTA_ERR; } } // namespace WebCore diff --git a/WebCore/storage/SQLStatement.h b/WebCore/storage/SQLStatement.h index f01f7bf..89af377 100644 --- a/WebCore/storage/SQLStatement.h +++ b/WebCore/storage/SQLStatement.h @@ -31,23 +31,18 @@ #if ENABLE(DATABASE) #include "PlatformString.h" - -#include "SQLError.h" #include "SQLResultSet.h" -#include "SQLStatementCallback.h" -#include "SQLStatementErrorCallback.h" #include "SQLValue.h" - -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> -#include <wtf/Threading.h> +#include <wtf/Forward.h> #include <wtf/Vector.h> namespace WebCore { class Database; +class SQLError; +class SQLStatementCallback; +class SQLStatementErrorCallback; class SQLTransaction; -class String; class SQLStatement : public ThreadSafeShared<SQLStatement> { public: @@ -66,7 +61,7 @@ public: SQLError* sqlError() const { return m_error.get(); } private: - SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, bool readOnly); + SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, bool readOnly); void setFailureDueToQuota(); void clearFailureDueToQuota(); diff --git a/WebCore/storage/SQLStatementCallback.h b/WebCore/storage/SQLStatementCallback.h index 31f5c0c..f86e29f 100644 --- a/WebCore/storage/SQLStatementCallback.h +++ b/WebCore/storage/SQLStatementCallback.h @@ -30,7 +30,7 @@ #if ENABLE(DATABASE) -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { @@ -40,7 +40,7 @@ class SQLResultSet; class SQLStatementCallback : public ThreadSafeShared<SQLStatementCallback> { public: virtual ~SQLStatementCallback() { } - virtual void handleEvent(SQLTransaction*, SQLResultSet*, bool& raisedException) = 0; + virtual bool handleEvent(SQLTransaction*, SQLResultSet*) = 0; }; } diff --git a/WebCore/storage/SQLStatementCallback.idl b/WebCore/storage/SQLStatementCallback.idl new file mode 100644 index 0000000..cc25711 --- /dev/null +++ b/WebCore/storage/SQLStatementCallback.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] SQLStatementCallback { + boolean handleEvent(in SQLTransaction transaction, in SQLResultSet resultSet); + }; +} diff --git a/WebCore/storage/SQLStatementErrorCallback.h b/WebCore/storage/SQLStatementErrorCallback.h index 29127ce..acb8f64 100644 --- a/WebCore/storage/SQLStatementErrorCallback.h +++ b/WebCore/storage/SQLStatementErrorCallback.h @@ -31,7 +31,7 @@ #if ENABLE(DATABASE) -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { diff --git a/WebCore/storage/SQLStatementErrorCallback.idl b/WebCore/storage/SQLStatementErrorCallback.idl new file mode 100644 index 0000000..315500d --- /dev/null +++ b/WebCore/storage/SQLStatementErrorCallback.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] SQLStatementErrorCallback { + [Custom] boolean handleEvent(in SQLTransaction transaction, in SQLError error); + }; +} diff --git a/WebCore/storage/SQLStatementSync.cpp b/WebCore/storage/SQLStatementSync.cpp new file mode 100644 index 0000000..e47919f --- /dev/null +++ b/WebCore/storage/SQLStatementSync.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SQLStatementSync.h" + +#if ENABLE(DATABASE) + +#include "DatabaseSync.h" +#include "SQLException.h" +#include "SQLResultSet.h" +#include "SQLValue.h" +#include "SQLiteDatabase.h" +#include "SQLiteStatement.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +SQLStatementSync::SQLStatementSync(const String& statement, const Vector<SQLValue>& arguments, bool readOnly) + : m_statement(statement) + , m_arguments(arguments) + , m_readOnly(readOnly) +{ + ASSERT(!m_statement.isEmpty()); +} + +PassRefPtr<SQLResultSet> SQLStatementSync::execute(DatabaseSync* db, ExceptionCode& ec) +{ + if (m_readOnly) + db->setAuthorizerReadOnly(); + + SQLiteDatabase* database = &db->sqliteDatabase(); + + SQLiteStatement statement(*database, m_statement); + int result = statement.prepare(); + if (result != SQLResultOk) { + ec = (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/WebCore/storage/SQLStatementSync.h b/WebCore/storage/SQLStatementSync.h new file mode 100644 index 0000000..dc0394c --- /dev/null +++ b/WebCore/storage/SQLStatementSync.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLStatementSync_h +#define SQLStatementSync_h + +#if ENABLE(DATABASE) + +#include "ExceptionCode.h" +#include "PlatformString.h" +#include "SQLValue.h" +#include <wtf/Forward.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class DatabaseSync; +class SQLResultSet; + +class SQLStatementSync { +public: + SQLStatementSync(const String& statement, const Vector<SQLValue>& arguments, bool readOnly); + + PassRefPtr<SQLResultSet> execute(DatabaseSync*, ExceptionCode&); + +private: + String m_statement; + Vector<SQLValue> m_arguments; + bool m_readOnly; +}; + +} // namespace WebCore + +#endif // ENABLE(DATABASE) + +#endif // SQLStatementSync_h diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp index 754cebc..feaa46e 100644 --- a/WebCore/storage/SQLTransaction.cpp +++ b/WebCore/storage/SQLTransaction.cpp @@ -31,26 +31,25 @@ #if ENABLE(DATABASE) -#include "ChromeClient.h" #include "Database.h" -#include "DatabaseAuthorizer.h" -#include "DatabaseDetails.h" #include "DatabaseThread.h" -#include "ExceptionCode.h" #include "Logging.h" -#include "Page.h" #include "PlatformString.h" #include "ScriptExecutionContext.h" -#include "Settings.h" #include "SQLError.h" #include "SQLiteTransaction.h" -#include "SQLResultSet.h" #include "SQLStatement.h" #include "SQLStatementCallback.h" #include "SQLStatementErrorCallback.h" +#include "SQLTransactionCallback.h" #include "SQLTransactionClient.h" #include "SQLTransactionCoordinator.h" +#include "SQLTransactionErrorCallback.h" #include "SQLValue.h" +#include "VoidCallback.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> // There's no way of knowing exactly how much more space will be required when a statement hits the quota limit. // For now, we'll arbitrarily choose currentQuota + 1mb. @@ -65,8 +64,8 @@ PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTr return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper, readOnly)); } -SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback, - PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) +SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, + PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) : m_nextStep(&SQLTransaction::acquireLock) , m_executeSqlAllowed(false) , m_database(db) @@ -89,7 +88,7 @@ SQLTransaction::~SQLTransaction() void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e) { - if (!m_executeSqlAllowed || m_database->stopped()) { + if (!m_executeSqlAllowed || !m_database->opened()) { e = INVALID_STATE_ERR; return; } @@ -147,17 +146,26 @@ const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod } #endif -void SQLTransaction::checkAndHandleClosedDatabase() +void SQLTransaction::checkAndHandleClosedOrInterruptedDatabase() { - if (!m_database->stopped()) + 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 - cancelling work for this transaction"); + 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(); @@ -180,7 +188,7 @@ bool SQLTransaction::performNextStep() m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback || m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback); - checkAndHandleClosedDatabase(); + checkAndHandleClosedOrInterruptedDatabase(); if (m_nextStep) (this->*m_nextStep)(); @@ -199,7 +207,7 @@ void SQLTransaction::performPendingCallback() m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback || m_nextStep == &SQLTransaction::deliverSuccessCallback); - checkAndHandleClosedDatabase(); + checkAndHandleClosedOrInterruptedDatabase(); if (m_nextStep) (this->*m_nextStep)(); @@ -230,45 +238,45 @@ void SQLTransaction::lockAcquired() void SQLTransaction::openTransactionAndPreflight() { - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); ASSERT(m_lockAcquired); LOG(StorageAPI, "Opening and preflighting transaction %p", this); // If the database was deleted, jump to the error callback if (m_database->deleted()) { - m_transactionError = SQLError::create(0, "unable to open a transaction, because the user deleted the database"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database"); handleTransactionError(false); return; } // Set the maximum usage for this transaction if this transactions is not read-only if (!m_readOnly) - m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize()); + m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); ASSERT(!m_sqliteTransaction); - m_sqliteTransaction.set(new SQLiteTransaction(m_database->m_sqliteDatabase, m_readOnly)); + m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); - m_database->m_databaseAuthorizer->disable(); + m_database->resetDeletes(); + m_database->disableAuthorizer(); m_sqliteTransaction->begin(); - m_database->m_databaseAuthorizer->enable(); + m_database->enableAuthorizer(); // Transaction Steps 1+2 - Open a transaction to the database, jumping to the error callback if that fails if (!m_sqliteTransaction->inProgress()) { - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_sqliteTransaction.clear(); - m_transactionError = SQLError::create(0, "unable to open a transaction to the database"); + m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to open a transaction to the database"); handleTransactionError(false); return; } // Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail if (m_wrapper && !m_wrapper->performPreflight(this)) { - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_sqliteTransaction.clear(); m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) - m_transactionError = SQLError::create(0, "unknown error occured setting up transaction"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction"); handleTransactionError(false); return; @@ -286,14 +294,14 @@ void SQLTransaction::deliverTransactionCallback() if (m_callback) { m_executeSqlAllowed = true; - m_callback->handleEvent(this, shouldDeliverErrorCallback); + shouldDeliverErrorCallback = !m_callback->handleEvent(this); m_executeSqlAllowed = false; - } else - shouldDeliverErrorCallback = true; + 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(0, "the SQLTransactionCallback was null or threw an exception"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception"); deliverTransactionErrorCallback(); } else scheduleToRunStatements(); @@ -322,7 +330,7 @@ void SQLTransaction::runStatements() // m_shouldRetryCurrentStatement is set to true only when a statement exceeds // the quota, which can happen only in a read-write transaction. Therefore, there // is no need to check here if the transaction is read-write. - m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize()); + m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); } else { // If the current statement has already been run, failed due to quota constraints, and we're not retrying it, // that means it ended in an error. Handle it now @@ -349,8 +357,7 @@ void SQLTransaction::getNextStatement() MutexLocker locker(m_statementMutex); if (!m_statementQueue.isEmpty()) { - m_currentStatement = m_statementQueue.first(); - m_statementQueue.removeFirst(); + m_currentStatement = m_statementQueue.takeFirst(); } } @@ -359,14 +366,14 @@ bool SQLTransaction::runCurrentStatement() if (!m_currentStatement) return false; - m_database->m_databaseAuthorizer->reset(); + m_database->resetAuthorizer(); if (m_currentStatement->execute(m_database.get())) { - if (m_database->m_databaseAuthorizer->lastActionChangedDatabase()) { + if (m_database->lastActionChangedDatabase()) { // Flag this transaction as having changed the database for later delegate notification m_modifiedDatabase = true; // Also dirty the size of this database file for calculating quota usage - m_database->transactionClient()->didExecuteStatement(this); + m_database->transactionClient()->didExecuteStatement(database()); } if (m_currentStatement->hasStatementCallback()) { @@ -401,7 +408,7 @@ void SQLTransaction::handleCurrentStatementError() } else { m_transactionError = m_currentStatement->sqlError(); if (!m_transactionError) - m_transactionError = SQLError::create(1, "the statement failed to execute"); + m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute"); handleTransactionError(false); } } @@ -417,7 +424,7 @@ void SQLTransaction::deliverStatementCallback() m_executeSqlAllowed = false; if (result) { - m_transactionError = SQLError::create(0, "the statement callback raised an exception or statement error callback did not return false"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false"); handleTransactionError(true); } else scheduleToRunStatements(); @@ -428,7 +435,7 @@ void SQLTransaction::deliverQuotaIncreaseCallback() ASSERT(m_currentStatement); ASSERT(!m_shouldRetryCurrentStatement); - m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(this); + m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database()); m_nextStep = &SQLTransaction::runStatements; LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this); @@ -443,7 +450,7 @@ void SQLTransaction::postflightAndCommit() if (m_wrapper && !m_wrapper->performPostflight(this)) { m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) - m_transactionError = SQLError::create(0, "unknown error occured setting up transaction"); + m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction"); handleTransactionError(false); return; } @@ -451,23 +458,27 @@ void SQLTransaction::postflightAndCommit() // Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails ASSERT(m_sqliteTransaction); - m_database->m_databaseAuthorizer->disable(); + m_database->disableAuthorizer(); m_sqliteTransaction->commit(); - m_database->m_databaseAuthorizer->enable(); + m_database->enableAuthorizer(); // If the commit failed, the transaction will still be marked as "in progress" if (m_sqliteTransaction->inProgress()) { - m_transactionError = SQLError::create(0, "failed to commit the transaction"); + m_successCallback = 0; + m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction"); handleTransactionError(false); return; } - // The commit was successful, notify the delegates if the transaction modified this database + // Vacuum the database if anything was deleted. + if (m_database->hadDeletes()) + m_database->incrementalVacuumIfNeeded(); + + // The commit was successful. If the transaction modified this database, notify the delegates. if (m_modifiedDatabase) - m_database->transactionClient()->didCommitTransaction(this); + m_database->transactionClient()->didCommitWriteTransaction(database()); // Now release our unneeded callbacks, to break reference cycles. - m_callback = 0; m_errorCallback = 0; // Transaction Step 10 - Deliver success callback, if there is one @@ -502,7 +513,7 @@ void SQLTransaction::cleanupAfterSuccessCallback() // Transaction Step 11 - End transaction steps // There is no next step LOG(StorageAPI, "Transaction %p is complete\n", this); - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_sqliteTransaction.clear(); m_nextStep = 0; @@ -540,8 +551,10 @@ void SQLTransaction::deliverTransactionErrorCallback() // Transaction Step 12 - If exists, invoke error callback with the last // error to have occurred in this transaction. - if (m_errorCallback) + 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); @@ -552,15 +565,15 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback() { ASSERT(m_lockAcquired); - m_database->m_databaseAuthorizer->disable(); + m_database->disableAuthorizer(); if (m_sqliteTransaction) { // Transaction Step 12 - Rollback the transaction. m_sqliteTransaction->rollback(); - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_sqliteTransaction.clear(); } - m_database->m_databaseAuthorizer->enable(); + m_database->enableAuthorizer(); // Transaction Step 12 - Any still-pending statements in the transaction are discarded. { @@ -570,13 +583,9 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback() // Transaction is complete! There is no next step LOG(StorageAPI, "Transaction %p is complete with an error\n", this); - ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_nextStep = 0; - // Now release our callbacks, to break reference cycles. - m_callback = 0; - m_errorCallback = 0; - // Now release the lock on this database m_database->transactionCoordinator()->releaseLock(this); } diff --git a/WebCore/storage/SQLTransaction.h b/WebCore/storage/SQLTransaction.h index 1b02d01..3eb1fd5 100644 --- a/WebCore/storage/SQLTransaction.h +++ b/WebCore/storage/SQLTransaction.h @@ -30,29 +30,24 @@ #if ENABLE(DATABASE) -#include <wtf/Threading.h> - -#include "SQLiteTransaction.h" +#include "ExceptionCode.h" #include "SQLStatement.h" -#include "SQLTransactionCallback.h" -#include "SQLTransactionErrorCallback.h" #include <wtf/Deque.h> #include <wtf/Forward.h> -#include <wtf/OwnPtr.h> -#include <wtf/RefPtr.h> +#include <wtf/ThreadSafeShared.h> #include <wtf/Vector.h> namespace WebCore { -typedef int ExceptionCode; - class Database; class SQLError; +class SQLiteTransaction; class SQLStatementCallback; class SQLStatementErrorCallback; class SQLTransaction; +class SQLTransactionCallback; +class SQLTransactionErrorCallback; class SQLValue; -class String; class VoidCallback; class SQLTransactionWrapper : public ThreadSafeShared<SQLTransactionWrapper> { @@ -72,7 +67,7 @@ public: ~SQLTransaction(); void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, - PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e); + PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, ExceptionCode&); void lockAcquired(); bool performNextStep(); @@ -91,7 +86,7 @@ private: void enqueueStatement(PassRefPtr<SQLStatement>); - void checkAndHandleClosedDatabase(); + void checkAndHandleClosedOrInterruptedDatabase(); void acquireLock(); void openTransactionAndPreflight(); diff --git a/WebCore/storage/SQLTransaction.idl b/WebCore/storage/SQLTransaction.idl index 7d694e8..4e353d3 100644 --- a/WebCore/storage/SQLTransaction.idl +++ b/WebCore/storage/SQLTransaction.idl @@ -30,7 +30,8 @@ module storage { interface [ Conditional=DATABASE, - OmitConstructor + OmitConstructor, + NoStaticTables ] SQLTransaction { [Custom] void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback, in SQLStatementErrorCallback errorCallback); }; diff --git a/WebCore/storage/SQLTransactionCallback.h b/WebCore/storage/SQLTransactionCallback.h index de3e85dc..aff6233 100644 --- a/WebCore/storage/SQLTransactionCallback.h +++ b/WebCore/storage/SQLTransactionCallback.h @@ -31,17 +31,16 @@ #if ENABLE(DATABASE) -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { class SQLTransaction; -class SQLError; class SQLTransactionCallback : public ThreadSafeShared<SQLTransactionCallback> { public: virtual ~SQLTransactionCallback() { } - virtual void handleEvent(SQLTransaction*, bool& raisedException) = 0; + virtual bool handleEvent(SQLTransaction*) = 0; }; } diff --git a/WebCore/storage/SQLTransactionCallback.idl b/WebCore/storage/SQLTransactionCallback.idl new file mode 100644 index 0000000..d1bc77c --- /dev/null +++ b/WebCore/storage/SQLTransactionCallback.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] SQLTransactionCallback { + boolean handleEvent(in SQLTransaction transaction); + }; +} diff --git a/WebCore/storage/SQLTransactionClient.cpp b/WebCore/storage/SQLTransactionClient.cpp index 6064c99..6b95606 100644 --- a/WebCore/storage/SQLTransactionClient.cpp +++ b/WebCore/storage/SQLTransactionClient.cpp @@ -33,39 +33,27 @@ #if ENABLE(DATABASE) -#include "Chrome.h" -#include "ChromeClient.h" -#include "Database.h" -#include "DatabaseThread.h" +#include "AbstractDatabase.h" #include "DatabaseTracker.h" -#include "Document.h" -#include "OriginQuotaManager.h" -#include "Page.h" -#include "SQLTransaction.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" namespace WebCore { -void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction) +void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database) { - ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID()); - Database* database = transaction->database(); DatabaseTracker::tracker().scheduleNotifyDatabaseChanged( database->securityOrigin(), database->stringIdentifier()); } -void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction) +void SQLTransactionClient::didExecuteStatement(AbstractDatabase* database) { - ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID()); - OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager()); - Locker<OriginQuotaManager> locker(manager); - manager.markDatabase(transaction->database()); + DatabaseTracker::tracker().databaseChanged(database); } -bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction) +bool SQLTransactionClient::didExceedQuota(AbstractDatabase* database) { - ASSERT(transaction->database()->scriptExecutionContext()->isContextThread()); - Database* database = transaction->database(); - + ASSERT(database->scriptExecutionContext()->isContextThread()); unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin()); database->scriptExecutionContext()->databaseExceededQuota(database->stringIdentifier()); unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin()); diff --git a/WebCore/storage/SQLTransactionClient.h b/WebCore/storage/SQLTransactionClient.h index 801647b..fed0657 100644 --- a/WebCore/storage/SQLTransactionClient.h +++ b/WebCore/storage/SQLTransactionClient.h @@ -37,16 +37,17 @@ namespace WebCore { - class SQLTransaction; - - // A client to the SQLTransaction class. Allows SQLTransaction to notify interested - // parties that certain things have happened in a transaction. - class SQLTransactionClient : public Noncopyable { - public: - void didCommitTransaction(SQLTransaction*); - void didExecuteStatement(SQLTransaction*); - bool didExceedQuota(SQLTransaction*); - }; +class AbstractDatabase; + +// A client to the SQLTransaction class. Allows SQLTransaction to notify interested +// parties that certain things have happened in a transaction. +class SQLTransactionClient : public Noncopyable { +public: + void didCommitWriteTransaction(AbstractDatabase*); + void didExecuteStatement(AbstractDatabase*); + bool didExceedQuota(AbstractDatabase*); +}; + } #endif // ENABLE(DATABASE) diff --git a/WebCore/storage/SQLTransactionCoordinator.cpp b/WebCore/storage/SQLTransactionCoordinator.cpp index 0fe5bda..104ea10 100644 --- a/WebCore/storage/SQLTransactionCoordinator.cpp +++ b/WebCore/storage/SQLTransactionCoordinator.cpp @@ -33,7 +33,6 @@ #if ENABLE(DATABASE) -#include "CString.h" #include "Database.h" #include "SQLTransaction.h" #include <wtf/Deque.h> @@ -58,8 +57,7 @@ void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& inf RefPtr<SQLTransaction> firstPendingTransaction = info.pendingTransactions.first(); if (firstPendingTransaction->isReadOnly()) { do { - firstPendingTransaction = info.pendingTransactions.first(); - info.pendingTransactions.removeFirst(); + firstPendingTransaction = info.pendingTransactions.takeFirst(); info.activeReadTransactions.add(firstPendingTransaction); firstPendingTransaction->lockAcquired(); } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly()); diff --git a/WebCore/storage/SQLTransactionCoordinator.h b/WebCore/storage/SQLTransactionCoordinator.h index a51084f..94360c0 100644 --- a/WebCore/storage/SQLTransactionCoordinator.h +++ b/WebCore/storage/SQLTransactionCoordinator.h @@ -33,12 +33,11 @@ #if ENABLE(DATABASE) -#include "CString.h" -#include "StringHash.h" #include <wtf/Deque.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/RefPtr.h> +#include <wtf/text/StringHash.h> namespace WebCore { diff --git a/WebCore/storage/SQLTransactionErrorCallback.h b/WebCore/storage/SQLTransactionErrorCallback.h index de99212..4095d6a 100644 --- a/WebCore/storage/SQLTransactionErrorCallback.h +++ b/WebCore/storage/SQLTransactionErrorCallback.h @@ -31,17 +31,17 @@ #if ENABLE(DATABASE) -#include <wtf/Threading.h> +#include <wtf/ThreadSafeShared.h> namespace WebCore { - class SQLError; +class SQLError; - class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> { - public: - virtual ~SQLTransactionErrorCallback() { } - virtual void handleEvent(SQLError*) = 0; - }; +class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> { +public: + virtual ~SQLTransactionErrorCallback() { } + virtual bool handleEvent(SQLError*) = 0; +}; } diff --git a/WebCore/storage/SQLTransactionErrorCallback.idl b/WebCore/storage/SQLTransactionErrorCallback.idl new file mode 100644 index 0000000..779ba69 --- /dev/null +++ b/WebCore/storage/SQLTransactionErrorCallback.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] SQLTransactionErrorCallback { + boolean handleEvent(in SQLError error); + }; +} diff --git a/WebCore/storage/SQLTransactionSync.cpp b/WebCore/storage/SQLTransactionSync.cpp new file mode 100644 index 0000000..87f1eff --- /dev/null +++ b/WebCore/storage/SQLTransactionSync.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SQLTransactionSync.h" + +#if ENABLE(DATABASE) + +#include "DatabaseSync.h" +#include "PlatformString.h" +#include "SQLException.h" +#include "SQLResultSet.h" +#include "SQLStatementSync.h" +#include "SQLTransactionClient.h" +#include "SQLTransactionSyncCallback.h" +#include "SQLValue.h" +#include "SQLiteTransaction.h" +#include "ScriptExecutionContext.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +PassRefPtr<SQLTransactionSync> SQLTransactionSync::create(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly) +{ + return adoptRef(new SQLTransactionSync(db, callback, readOnly)); +} + +SQLTransactionSync::SQLTransactionSync(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly) + : m_database(db) + , m_callback(callback) + , m_readOnly(readOnly) + , m_modifiedDatabase(false) + , m_transactionClient(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; + + bool readOnlyMode = m_readOnly || m_database->scriptExecutionContext()->isDatabaseReadOnly(); + SQLStatementSync statement(sqlStatement, arguments, readOnlyMode); + + m_database->resetAuthorizer(); + bool retryStatement = true; + RefPtr<SQLResultSet> resultSet; + while (retryStatement) { + retryStatement = false; + resultSet = statement.execute(m_database.get(), ec); + if (!resultSet) { + if (m_sqliteTransaction->wasRolledBackBySqlite()) + return 0; + + if (ec == SQLException::QUOTA_ERR) { + if (m_transactionClient->didExceedQuota(database())) { + ec = 0; + retryStatement = true; + } else + return 0; + } + } + } + + if (m_database->lastActionChangedDatabase()) { + m_modifiedDatabase = true; + m_transactionClient->didExecuteStatement(database()); + } + + return resultSet.release(); +} + +ExceptionCode SQLTransactionSync::begin() +{ + ASSERT(m_database->scriptExecutionContext()->isContextThread()); + if (!m_database->opened()) + return SQLException::UNKNOWN_ERR; + + ASSERT(!m_database->sqliteDatabase().transactionInProgress()); + + // Set the maximum usage for this transaction if this transactions is not read-only. + if (!m_readOnly) + m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); + + ASSERT(!m_sqliteTransaction); + m_sqliteTransaction = 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/WebCore/storage/SQLTransactionSync.h b/WebCore/storage/SQLTransactionSync.h new file mode 100644 index 0000000..e66c876 --- /dev/null +++ b/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/WebCore/storage/SQLTransactionSync.idl b/WebCore/storage/SQLTransactionSync.idl new file mode 100644 index 0000000..003a21d --- /dev/null +++ b/WebCore/storage/SQLTransactionSync.idl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + + interface [ + Conditional=DATABASE, + OmitConstructor, + NoStaticTables + ] SQLTransactionSync { + [Custom] SQLResultSet executeSql(in DOMString sqlStatement, in ObjectArray arguments); + }; +} diff --git a/WebCore/storage/SQLTransactionSyncCallback.h b/WebCore/storage/SQLTransactionSyncCallback.h new file mode 100644 index 0000000..f22e62f --- /dev/null +++ b/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/WebCore/storage/SQLTransactionSyncCallback.idl b/WebCore/storage/SQLTransactionSyncCallback.idl new file mode 100644 index 0000000..b0fffca --- /dev/null +++ b/WebCore/storage/SQLTransactionSyncCallback.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module storage { + interface [ + Conditional=DATABASE, + Callback + ] SQLTransactionSyncCallback { + boolean handleEvent(in SQLTransactionSync transaction); + }; +} diff --git a/WebCore/storage/Storage.h b/WebCore/storage/Storage.h index 06cc97b..c81481a 100644 --- a/WebCore/storage/Storage.h +++ b/WebCore/storage/Storage.h @@ -36,7 +36,6 @@ namespace WebCore { class Frame; class StorageArea; - class String; typedef int ExceptionCode; class Storage : public RefCounted<Storage> { diff --git a/WebCore/storage/StorageAreaImpl.cpp b/WebCore/storage/StorageAreaImpl.cpp index aa04781..dc25e54 100644 --- a/WebCore/storage/StorageAreaImpl.cpp +++ b/WebCore/storage/StorageAreaImpl.cpp @@ -44,12 +44,7 @@ StorageAreaImpl::~StorageAreaImpl() ASSERT(isMainThread()); } -PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) -{ - return adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota)); -} - -StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) +inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) : m_storageType(storageType) , m_securityOrigin(origin) , m_storageMap(StorageMap::create(quota)) @@ -61,13 +56,20 @@ StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOri ASSERT(isMainThread()); ASSERT(m_securityOrigin); ASSERT(m_storageMap); +} + +PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) +{ + RefPtr<StorageAreaImpl> area = adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota)); // FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing, - // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894 - if (m_storageSyncManager) { - m_storageAreaSync = StorageAreaSync::create(m_storageSyncManager, this, m_securityOrigin->databaseIdentifier()); - ASSERT(m_storageAreaSync); + // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894 + if (area->m_storageSyncManager) { + area->m_storageAreaSync = StorageAreaSync::create(area->m_storageSyncManager, area.get(), area->m_securityOrigin->databaseIdentifier()); + ASSERT(area->m_storageAreaSync); } + + return area.release(); } PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy() diff --git a/WebCore/storage/StorageAreaSync.cpp b/WebCore/storage/StorageAreaSync.cpp index d4eba76..f2008ab 100644 --- a/WebCore/storage/StorageAreaSync.cpp +++ b/WebCore/storage/StorageAreaSync.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,14 +28,16 @@ #if ENABLE(DOM_STORAGE) -#include "CString.h" #include "EventNames.h" +#include "FileSystem.h" #include "HTMLElement.h" -#include "SecurityOrigin.h" +#include "SQLiteFileSystem.h" #include "SQLiteStatement.h" +#include "SecurityOrigin.h" #include "StorageAreaImpl.h" #include "StorageSyncManager.h" #include "SuddenTermination.h" +#include <wtf/text/CString.h> namespace WebCore { @@ -43,12 +45,11 @@ namespace WebCore { // Instead, queue up a batch of items to sync and actually do the sync at the following interval. static const double StorageSyncInterval = 1.0; -PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier) -{ - return adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier)); -} +// A sane limit on how many items we'll schedule to sync all at once. This makes it +// much harder to starve the rest of LocalStorage and the OS's IO subsystem in general. +static const int MaxiumItemsToSync = 100; -StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier) +inline StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier) : m_syncTimer(this, &StorageAreaSync::syncTimerFired) , m_itemsCleared(false) , m_finalSyncScheduled(false) @@ -57,16 +58,25 @@ StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManag , m_databaseIdentifier(databaseIdentifier.crossThreadString()) , m_clearItemsWhileSyncing(false) , m_syncScheduled(false) + , m_syncInProgress(false) + , m_databaseOpenFailed(false) , m_importComplete(false) { ASSERT(isMainThread()); ASSERT(m_storageArea); ASSERT(m_syncManager); +} + +PassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier) +{ + RefPtr<StorageAreaSync> area = adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier)); // FIXME: If it can't import, then the default WebKit behavior should be that of private browsing, - // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894 - if (!m_syncManager->scheduleImport(this)) - m_importComplete = true; + // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894 + if (!area->m_syncManager->scheduleImport(area.get())) + area->m_importComplete = true; + + return area.release(); } StorageAreaSync::~StorageAreaSync() @@ -92,8 +102,9 @@ void StorageAreaSync::scheduleFinalSync() } // FIXME: This is synchronous. We should do it on the background process, but // we should do it safely. - syncTimerFired(&m_syncTimer); m_finalSyncScheduled = true; + syncTimerFired(&m_syncTimer); + m_syncManager->scheduleDeleteEmptyDatabase(this); } void StorageAreaSync::scheduleItemForSync(const String& key, const String& value) @@ -131,20 +142,43 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*) { ASSERT(isMainThread()); - HashMap<String, String>::iterator it = m_changedItems.begin(); - HashMap<String, String>::iterator end = m_changedItems.end(); - + bool partialSync = false; { MutexLocker locker(m_syncLock); + // Do not schedule another sync if we're still trying to complete the + // previous one. But, if we're shutting down, schedule it anyway. + if (m_syncInProgress && !m_finalSyncScheduled) { + ASSERT(!m_syncTimer.isActive()); + m_syncTimer.startOneShot(StorageSyncInterval); + return; + } + if (m_itemsCleared) { m_itemsPendingSync.clear(); m_clearItemsWhileSyncing = true; m_itemsCleared = false; } - for (; it != end; ++it) - m_itemsPendingSync.set(it->first.crossThreadString(), it->second.crossThreadString()); + HashMap<String, String>::iterator changed_it = m_changedItems.begin(); + HashMap<String, String>::iterator changed_end = m_changedItems.end(); + for (int count = 0; changed_it != changed_end; ++count, ++changed_it) { + if (count >= MaxiumItemsToSync && !m_finalSyncScheduled) { + partialSync = true; + break; + } + m_itemsPendingSync.set(changed_it->first.crossThreadString(), changed_it->second.crossThreadString()); + } + + if (partialSync) { + // We can't do the fast path of simply clearing all items, so we'll need to manually + // remove them one by one. Done under lock since m_itemsPendingSync is modified by + // the background thread. + HashMap<String, String>::iterator pending_it = m_itemsPendingSync.begin(); + HashMap<String, String>::iterator pending_end = m_itemsPendingSync.end(); + for (; pending_it != pending_end; ++pending_it) + m_changedItems.remove(pending_it->first); + } if (!m_syncScheduled) { m_syncScheduled = true; @@ -157,35 +191,60 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*) } } - // The following is balanced by the calls to disableSuddenTermination in the - // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions. - enableSuddenTermination(); + if (partialSync) { + // If we didn't finish syncing, then we need to finish the job later. + ASSERT(!m_syncTimer.isActive()); + m_syncTimer.startOneShot(StorageSyncInterval); + } else { + // The following is balanced by the calls to disableSuddenTermination in the + // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions. + enableSuddenTermination(); - m_changedItems.clear(); + m_changedItems.clear(); + } } -void StorageAreaSync::performImport() +void StorageAreaSync::openDatabase(OpenDatabaseParamType openingStrategy) { ASSERT(!isMainThread()); ASSERT(!m_database.isOpen()); + ASSERT(!m_databaseOpenFailed); String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier); + if (!fileExists(databaseFilename) && openingStrategy == SkipIfNonExistent) + return; + if (databaseFilename.isEmpty()) { LOG_ERROR("Filename for local storage database is empty - cannot open for persistent storage"); markImported(); + m_databaseOpenFailed = true; return; } if (!m_database.open(databaseFilename)) { LOG_ERROR("Failed to open database file %s for local storage", databaseFilename.utf8().data()); markImported(); + m_databaseOpenFailed = true; return; } if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL)")) { LOG_ERROR("Failed to create table ItemTable for local storage"); markImported(); + m_databaseOpenFailed = true; + return; + } +} + +void StorageAreaSync::performImport() +{ + ASSERT(!isMainThread()); + ASSERT(!m_database.isOpen()); + + openDatabase(SkipIfNonExistent); + if (!m_database.isOpen()) { + markImported(); return; } @@ -251,6 +310,12 @@ void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items { ASSERT(!isMainThread()); + if (items.isEmpty() && !clearItems) + return; + if (m_databaseOpenFailed) + return; + if (!m_database.isOpen()) + openDatabase(CreateIfNonExistent); if (!m_database.isOpen()) return; @@ -319,15 +384,49 @@ void StorageAreaSync::performSync() m_clearItemsWhileSyncing = false; m_syncScheduled = false; + m_syncInProgress = true; } sync(clearItems, items); + { + MutexLocker locker(m_syncLock); + m_syncInProgress = false; + } + // The following is balanced by the call to disableSuddenTermination in the // syncTimerFired function. enableSuddenTermination(); } +void StorageAreaSync::deleteEmptyDatabase() +{ + ASSERT(!isMainThread()); + if (!m_database.isOpen()) + return; + + SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable"); + if (query.prepare() != SQLResultOk) { + LOG_ERROR("Unable to count number of rows in ItemTable for local storage"); + return; + } + + int result = query.step(); + if (result != SQLResultRow) { + LOG_ERROR("No results when counting number of rows in ItemTable for local storage"); + return; + } + + int count = query.getColumnInt(0); + if (!count) { + query.finalize(); + m_database.close(); + String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier); + if (!SQLiteFileSystem::deleteDatabaseFile(databaseFilename)) + LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data()); + } +} + } // namespace WebCore #endif // ENABLE(DOM_STORAGE) diff --git a/WebCore/storage/StorageAreaSync.h b/WebCore/storage/StorageAreaSync.h index 9afdfde..90aa6a7 100644 --- a/WebCore/storage/StorageAreaSync.h +++ b/WebCore/storage/StorageAreaSync.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,11 +28,10 @@ #if ENABLE(DOM_STORAGE) -#include "PlatformString.h" #include "SQLiteDatabase.h" -#include "StringHash.h" #include "Timer.h" #include <wtf/HashMap.h> +#include <wtf/text/StringHash.h> namespace WebCore { @@ -42,7 +41,7 @@ namespace WebCore { class StorageAreaSync : public RefCounted<StorageAreaSync> { public: - static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier); + static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier); ~StorageAreaSync(); void scheduleFinalSync(); @@ -52,7 +51,7 @@ namespace WebCore { void scheduleClear(); private: - StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, String databaseIdentifier); + StorageAreaSync(PassRefPtr<StorageSyncManager>, PassRefPtr<StorageAreaImpl>, const String& databaseIdentifier); void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame); @@ -73,9 +72,16 @@ namespace WebCore { // Called from the background thread void performImport(); void performSync(); + void deleteEmptyDatabase(); private: + enum OpenDatabaseParamType { + CreateIfNonExistent, + SkipIfNonExistent + }; + void syncTimerFired(Timer<StorageAreaSync>*); + void openDatabase(OpenDatabaseParamType openingStrategy); void sync(bool clearItems, const HashMap<String, String>& items); const String m_databaseIdentifier; @@ -84,6 +90,8 @@ namespace WebCore { HashMap<String, String> m_itemsPendingSync; bool m_clearItemsWhileSyncing; bool m_syncScheduled; + bool m_syncInProgress; + bool m_databaseOpenFailed; mutable Mutex m_importLock; mutable ThreadCondition m_importCondition; diff --git a/WebCore/storage/StorageEvent.cpp b/WebCore/storage/StorageEvent.cpp index 126aca0..a08cde2 100644 --- a/WebCore/storage/StorageEvent.cpp +++ b/WebCore/storage/StorageEvent.cpp @@ -41,22 +41,26 @@ StorageEvent::StorageEvent() { } -PassRefPtr<StorageEvent> StorageEvent::create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea) +StorageEvent::~StorageEvent() { - return adoptRef(new StorageEvent(type, key, oldValue, newValue, uri, storageArea)); } -StorageEvent::StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea) +PassRefPtr<StorageEvent> StorageEvent::create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea) +{ + return adoptRef(new StorageEvent(type, key, oldValue, newValue, url, storageArea)); +} + +StorageEvent::StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea) : Event(type, false, false) , m_key(key) , m_oldValue(oldValue) , m_newValue(newValue) - , m_uri(uri) + , m_url(url) , m_storageArea(storageArea) { } -void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea) +void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea) { if (dispatched()) return; @@ -66,7 +70,7 @@ void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bo m_key = key; m_oldValue = oldValue; m_newValue = newValue; - m_uri = uri; + m_url = url; m_storageArea = storageArea; } diff --git a/WebCore/storage/StorageEvent.h b/WebCore/storage/StorageEvent.h index fa7535b..8e558a8 100644 --- a/WebCore/storage/StorageEvent.h +++ b/WebCore/storage/StorageEvent.h @@ -38,29 +38,30 @@ namespace WebCore { class StorageEvent : public Event { public: static PassRefPtr<StorageEvent> create(); - static PassRefPtr<StorageEvent> create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea); + static PassRefPtr<StorageEvent> create(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea); + virtual ~StorageEvent(); const String& key() const { return m_key; } const String& oldValue() const { return m_oldValue; } const String& newValue() const { return m_newValue; } - const String& uri() const { return m_uri; } + const String& url() const { return m_url; } Storage* storageArea() const { return m_storageArea.get(); } - void initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea); + void initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea); // Needed once we support init<blank>EventNS - // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString uriArg, Storage storageAreaArg); + // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, Storage storageAreaArg); virtual bool isStorageEvent() const { return true; } private: StorageEvent(); - StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, Storage* storageArea); + StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea); String m_key; String m_oldValue; String m_newValue; - String m_uri; + String m_url; RefPtr<Storage> m_storageArea; }; diff --git a/WebCore/storage/StorageEvent.idl b/WebCore/storage/StorageEvent.idl index 3e77eda..3464caa 100644 --- a/WebCore/storage/StorageEvent.idl +++ b/WebCore/storage/StorageEvent.idl @@ -31,12 +31,12 @@ module storage { readonly attribute [ConvertNullStringTo=Null] DOMString key; readonly attribute [ConvertNullStringTo=Null] DOMString oldValue; readonly attribute [ConvertNullStringTo=Null] DOMString newValue; - readonly attribute DOMString uri; + readonly attribute DOMString url; readonly attribute Storage storageArea; - void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in [ConvertNullToNullString] DOMString oldValueArg, in [ConvertNullToNullString] DOMString newValueArg, in DOMString uriArg, in Storage storageAreaArg); + void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in [ConvertNullToNullString] DOMString oldValueArg, in [ConvertNullToNullString] DOMString newValueArg, in DOMString urlArg, in Storage storageAreaArg); // Needed once we support init<blank>EventNS - // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString uriArg, in Storage storageAreaArg); + // void initStorageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, in Storage storageAreaArg); }; } diff --git a/WebCore/storage/StorageEventDispatcher.cpp b/WebCore/storage/StorageEventDispatcher.cpp index dc0295b..5833c59 100644 --- a/WebCore/storage/StorageEventDispatcher.cpp +++ b/WebCore/storage/StorageEventDispatcher.cpp @@ -54,8 +54,12 @@ void StorageEventDispatcher::dispatch(const String& key, const String& oldValue, frames.append(frame); } - for (unsigned i = 0; i < frames.size(); ++i) - frames[i]->document()->enqueueStorageEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->sessionStorage())); + for (unsigned i = 0; i < frames.size(); ++i) { + ExceptionCode ec = 0; + Storage* storage = frames[i]->domWindow()->sessionStorage(ec); + if (!ec) + frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage)); + } } else { // Send events to every page. const HashSet<Page*>& pages = page->group().pages(); @@ -67,8 +71,12 @@ void StorageEventDispatcher::dispatch(const String& key, const String& oldValue, } } - for (unsigned i = 0; i < frames.size(); ++i) - frames[i]->document()->enqueueStorageEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), frames[i]->domWindow()->localStorage())); + for (unsigned i = 0; i < frames.size(); ++i) { + ExceptionCode ec = 0; + Storage* storage = frames[i]->domWindow()->localStorage(ec); + if (!ec) + frames[i]->document()->enqueueEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage)); + } } } diff --git a/WebCore/storage/StorageMap.h b/WebCore/storage/StorageMap.h index fa5f46c..d162124 100644 --- a/WebCore/storage/StorageMap.h +++ b/WebCore/storage/StorageMap.h @@ -29,11 +29,10 @@ #if ENABLE(DOM_STORAGE) #include "PlatformString.h" -#include "StringHash.h" - #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +#include <wtf/text/StringHash.h> namespace WebCore { diff --git a/WebCore/storage/StorageNamespace.cpp b/WebCore/storage/StorageNamespace.cpp index b54ba16..ce36608 100644 --- a/WebCore/storage/StorageNamespace.cpp +++ b/WebCore/storage/StorageNamespace.cpp @@ -42,9 +42,9 @@ PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const Strin } // The page argument is only used by the Chromium port. -PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*) +PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace(Page*, unsigned quota) { - return StorageNamespaceImpl::sessionStorageNamespace(); + return StorageNamespaceImpl::sessionStorageNamespace(quota); } } // namespace WebCore diff --git a/WebCore/storage/StorageNamespace.h b/WebCore/storage/StorageNamespace.h index e84e5a6..8f09b1a 100644 --- a/WebCore/storage/StorageNamespace.h +++ b/WebCore/storage/StorageNamespace.h @@ -43,7 +43,7 @@ class StorageArea; class StorageNamespace : public RefCounted<StorageNamespace> { public: static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota); - static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*); + static PassRefPtr<StorageNamespace> sessionStorageNamespace(Page*, unsigned quota); virtual ~StorageNamespace() { } virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0; diff --git a/WebCore/storage/StorageNamespaceImpl.cpp b/WebCore/storage/StorageNamespaceImpl.cpp index 19ff6b4..3a21489 100644 --- a/WebCore/storage/StorageNamespaceImpl.cpp +++ b/WebCore/storage/StorageNamespaceImpl.cpp @@ -29,11 +29,11 @@ #if ENABLE(DOM_STORAGE) #include "SecurityOriginHash.h" -#include "StringHash.h" #include "StorageAreaImpl.h" #include "StorageMap.h" #include "StorageSyncManager.h" #include <wtf/StdLibExtras.h> +#include <wtf/text/StringHash.h> namespace WebCore { @@ -58,9 +58,9 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const S return it->second; } -PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace() +PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(unsigned quota) { - return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), StorageMap::noQuota)); + return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), quota)); } StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota) @@ -93,12 +93,12 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy() ASSERT(!m_isShutdown); ASSERT(m_storageType == SessionStorage); - StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path, m_quota); + 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 adoptRef(newNamespace); + return newNamespace.release(); } PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin) @@ -108,7 +108,7 @@ PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOri RefPtr<SecurityOrigin> origin = prpOrigin; RefPtr<StorageAreaImpl> storageArea; - if (storageArea = m_storageAreaMap.get(origin)) + if ((storageArea = m_storageAreaMap.get(origin))) return storageArea.release(); storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota); @@ -119,7 +119,9 @@ PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOri void StorageNamespaceImpl::close() { ASSERT(isMainThread()); - ASSERT(!m_isShutdown); + + if (m_isShutdown) + return; // If we're session storage, we shouldn't need to do any work here. if (m_storageType == SessionStorage) { diff --git a/WebCore/storage/StorageNamespaceImpl.h b/WebCore/storage/StorageNamespaceImpl.h index b81b55a..5221add 100644 --- a/WebCore/storage/StorageNamespaceImpl.h +++ b/WebCore/storage/StorageNamespaceImpl.h @@ -43,7 +43,7 @@ namespace WebCore { class StorageNamespaceImpl : public StorageNamespace { public: static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota); - static PassRefPtr<StorageNamespace> sessionStorageNamespace(); + static PassRefPtr<StorageNamespace> sessionStorageNamespace(unsigned quota); virtual ~StorageNamespaceImpl(); virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>); diff --git a/WebCore/storage/StorageSyncManager.cpp b/WebCore/storage/StorageSyncManager.cpp index d9641b7..1cf8306 100644 --- a/WebCore/storage/StorageSyncManager.cpp +++ b/WebCore/storage/StorageSyncManager.cpp @@ -28,7 +28,6 @@ #if ENABLE(DOM_STORAGE) -#include "CString.h" #include "EventNames.h" #include "FileSystem.h" #include "Frame.h" @@ -38,6 +37,7 @@ #include "Page.h" #include "PageGroup.h" #include "StorageAreaSync.h" +#include <wtf/text/CString.h> #include <wtf/StdLibExtras.h> namespace WebCore { @@ -100,6 +100,13 @@ void StorageSyncManager::scheduleSync(PassRefPtr<StorageAreaSync> area) m_thread->scheduleTask(LocalStorageTask::createSync(area.get())); } +void StorageSyncManager::scheduleDeleteEmptyDatabase(PassRefPtr<StorageAreaSync> area) +{ + ASSERT(isMainThread()); + ASSERT(m_thread); + if (m_thread) + m_thread->scheduleTask(LocalStorageTask::createDeleteEmptyDatabase(area.get())); +} } // namespace WebCore #endif // ENABLE(DOM_STORAGE) diff --git a/WebCore/storage/StorageSyncManager.h b/WebCore/storage/StorageSyncManager.h index e2dfa76..6fbb75d 100644 --- a/WebCore/storage/StorageSyncManager.h +++ b/WebCore/storage/StorageSyncManager.h @@ -47,6 +47,7 @@ namespace WebCore { bool scheduleImport(PassRefPtr<StorageAreaSync>); void scheduleSync(PassRefPtr<StorageAreaSync>); + void scheduleDeleteEmptyDatabase(PassRefPtr<StorageAreaSync>); void close(); diff --git a/WebCore/storage/chromium/DatabaseObserver.h b/WebCore/storage/chromium/DatabaseObserver.h index 535c0d2..deb8036 100644 --- a/WebCore/storage/chromium/DatabaseObserver.h +++ b/WebCore/storage/chromium/DatabaseObserver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,19 +31,27 @@ #ifndef DatabaseObserver_h #define DatabaseObserver_h +#if ENABLE(DATABASE) + +#include <wtf/Forward.h> + namespace WebCore { -class Database; +class AbstractDatabase; +class ScriptExecutionContext; // The implementation of this class is in the WebKit API (Chromium source tree) -// in webkit/api/src/DatabaseObserver.cpp. +// in WebKit/chromium/src/DatabaseObserver.cpp. class DatabaseObserver { public: - static void databaseOpened(Database*); - static void databaseModified(Database*); - static void databaseClosed(Database*); + static bool canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long); + static void databaseOpened(AbstractDatabase*); + static void databaseModified(AbstractDatabase*); + static void databaseClosed(AbstractDatabase*); }; } +#endif // ENABLE(DATABASE) + #endif // DatabaseObserver_h diff --git a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp index ac58e07..361e203 100644 --- a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp +++ b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,37 +31,34 @@ #include "config.h" #include "DatabaseTracker.h" -#include "CString.h" -#include "Database.h" +#if ENABLE(DATABASE) + +#include "AbstractDatabase.h" #include "DatabaseObserver.h" -#include "DatabaseThread.h" #include "QuotaTracker.h" +#include "PlatformString.h" #include "ScriptExecutionContext.h" #include "SecurityOrigin.h" #include "SecurityOriginHash.h" #include "SQLiteFileSystem.h" -#include <wtf/HashSet.h> -#include <wtf/MainThread.h> #include <wtf/StdLibExtras.h> namespace WebCore { DatabaseTracker& DatabaseTracker::tracker() { - DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ()); + DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ("")); return tracker; } -DatabaseTracker::DatabaseTracker() +DatabaseTracker::DatabaseTracker(const String&) { SQLiteFileSystem::registerSQLiteVFS(); } -bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long) +bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* scriptExecutionContext, const String& name, const String& displayName, unsigned long estimatedSize) { - // In Chromium, a database can always be established (even though we might not - // be able to write anything to it if the quota for this origin was exceeded) - return true; + return DatabaseObserver::canEstablishDatabase(scriptExecutionContext, name, displayName, estimatedSize); } void DatabaseTracker::setDatabaseDetails(SecurityOrigin*, const String&, const String&, unsigned long) @@ -74,7 +71,7 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String return origin->databaseIdentifier() + "/" + name + "#"; } -void DatabaseTracker::addOpenDatabase(Database* database) +void DatabaseTracker::addOpenDatabase(AbstractDatabase* database) { ASSERT(database->scriptExecutionContext()->isContextThread()); MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); @@ -101,7 +98,7 @@ void DatabaseTracker::addOpenDatabase(Database* database) class TrackerRemoveOpenDatabaseTask : public ScriptExecutionContext::Task { public: - static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<Database> database) + static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<AbstractDatabase> database) { return new TrackerRemoveOpenDatabaseTask(database); } @@ -112,15 +109,15 @@ public: } private: - TrackerRemoveOpenDatabaseTask(PassRefPtr<Database> database) + TrackerRemoveOpenDatabaseTask(PassRefPtr<AbstractDatabase> database) : m_database(database) { } - RefPtr<Database> m_database; + RefPtr<AbstractDatabase> m_database; }; -void DatabaseTracker::removeOpenDatabase(Database* database) +void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database) { if (!database->scriptExecutionContext()->isContextThread()) { database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database)); @@ -149,7 +146,7 @@ void DatabaseTracker::removeOpenDatabase(Database* database) } -void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database> >* databases) +void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) @@ -167,9 +164,8 @@ void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam databases->add(*it); } -unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database) +unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database) { - ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID()); unsigned long long spaceAvailable = 0; unsigned long long databaseSize = 0; QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin( @@ -178,4 +174,35 @@ unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* databa 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/WebCore/storage/IndexedDatabaseRequest.cpp b/WebCore/storage/chromium/IDBFactoryBackendInterface.cpp index 827493b..016cab0 100644 --- a/WebCore/storage/IndexedDatabaseRequest.cpp +++ b/WebCore/storage/chromium/IDBFactoryBackendInterface.cpp @@ -26,25 +26,17 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "IndexedDatabaseRequest.h" +#include "IDBFactoryBackendInterface.h" -#if ENABLE(INDEXED_DATABASE) +#include "ChromiumBridge.h" -#include "ExceptionCode.h" -#include "IDBRequest.h" +#if ENABLE(INDEXED_DATABASE) namespace WebCore { -IndexedDatabaseRequest::IndexedDatabaseRequest() -{ -} - -IndexedDatabaseRequest::~IndexedDatabaseRequest() -{ -} - -void IndexedDatabaseRequest::open(const String& name, const String& description, bool modifyDatabase, ExceptionCode& exception) +PassRefPtr<IDBFactoryBackendInterface> IDBFactoryBackendInterface::create() { + return ChromiumBridge::idbFactory(); } } // namespace WebCore diff --git a/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp b/WebCore/storage/chromium/IDBKeyPathBackendImpl.cpp new file mode 100644 index 0000000..0f10875 --- /dev/null +++ b/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/WebCore/storage/chromium/QuotaTracker.cpp b/WebCore/storage/chromium/QuotaTracker.cpp index b49639d..3f48682 100644 --- a/WebCore/storage/chromium/QuotaTracker.cpp +++ b/WebCore/storage/chromium/QuotaTracker.cpp @@ -31,7 +31,8 @@ #include "config.h" #include "QuotaTracker.h" -#include "CString.h" +#if ENABLE(DATABASE) + #include <wtf/StdLibExtras.h> namespace WebCore { @@ -67,3 +68,5 @@ void QuotaTracker::updateDatabaseSizeAndSpaceAvailableToOrigin( } } + +#endif // ENABLE(DATABASE) diff --git a/WebCore/storage/chromium/QuotaTracker.h b/WebCore/storage/chromium/QuotaTracker.h index 9146910..774475e 100644 --- a/WebCore/storage/chromium/QuotaTracker.h +++ b/WebCore/storage/chromium/QuotaTracker.h @@ -31,10 +31,12 @@ #ifndef QuotaTracker_h #define QuotaTracker_h -#include "CString.h" +#if ENABLE(DATABASE) + +#include "PlatformString.h" #include "SecurityOrigin.h" -#include "StringHash.h" #include <wtf/HashMap.h> +#include <wtf/text/StringHash.h> namespace WebCore { @@ -60,4 +62,6 @@ private: } +#endif // ENABLE(DATABASE) + #endif // QuotaTracker_h diff --git a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp index a10ca3e..6a10821 100644 --- a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp +++ b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp @@ -31,18 +31,17 @@ #include "config.h" #include "SQLTransactionClient.h" -#include "Database.h" +#if ENABLE(DATABASE) + +#include "AbstractDatabase.h" #include "DatabaseObserver.h" -#include "DatabaseThread.h" -#include "Document.h" -#include "SQLTransaction.h" -#include <wtf/MainThread.h> +#include "ScriptExecutionContext.h" namespace WebCore { class NotifyDatabaseChangedTask : public ScriptExecutionContext::Task { public: - static PassOwnPtr<NotifyDatabaseChangedTask> create(Database *database) + static PassOwnPtr<NotifyDatabaseChangedTask> create(AbstractDatabase *database) { return new NotifyDatabaseChangedTask(database); } @@ -53,35 +52,38 @@ public: } private: - NotifyDatabaseChangedTask(PassRefPtr<Database> database) + NotifyDatabaseChangedTask(PassRefPtr<AbstractDatabase> database) : m_database(database) { } - RefPtr<Database> m_database; + RefPtr<AbstractDatabase> m_database; }; -void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction) +void SQLTransactionClient::didCommitWriteTransaction(AbstractDatabase* database) { - ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID()); - if (!transaction->isReadOnly()) { - transaction->database()->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(transaction->database())); + if (!database->scriptExecutionContext()->isContextThread()) { + database->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(database)); + return; } + + WebCore::DatabaseObserver::databaseModified(database); } -void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction) +void SQLTransactionClient::didExecuteStatement(AbstractDatabase* database) { // This method is called after executing every statement that changes the DB. // Chromium doesn't need to do anything at that point. - ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID()); } -bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction) +bool SQLTransactionClient::didExceedQuota(AbstractDatabase* database) { // Chromium does not allow users to manually change the quota for an origin (for now, at least). // Don't do anything. - ASSERT(transaction->database()->scriptExecutionContext()->isContextThread()); + ASSERT(database->scriptExecutionContext()->isContextThread()); return false; } } + +#endif // ENABLE(DATABASE) |