summaryrefslogtreecommitdiffstats
path: root/WebCore/storage
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2010-11-04 12:00:17 -0700
committerJohn Reck <jreck@google.com>2010-11-09 11:35:04 -0800
commite14391e94c850b8bd03680c23b38978db68687a8 (patch)
tree3fed87e6620fecaf3edc7259ae58a11662bedcb2 /WebCore/storage
parent1bd705833a68f07850cf7e204b26f8d328d16951 (diff)
downloadexternal_webkit-e14391e94c850b8bd03680c23b38978db68687a8.zip
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.gz
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.bz2
Merge Webkit at r70949: Initial merge by git.
Change-Id: I77b8645c083b5d0da8dba73ed01d4014aab9848e
Diffstat (limited to 'WebCore/storage')
-rw-r--r--WebCore/storage/IDBDatabaseBackendImpl.cpp85
-rw-r--r--WebCore/storage/IDBDatabaseBackendImpl.h13
-rw-r--r--WebCore/storage/IDBDatabaseException.h3
-rw-r--r--WebCore/storage/IDBDatabaseException.idl3
-rw-r--r--WebCore/storage/IDBFactoryBackendImpl.cpp77
-rw-r--r--WebCore/storage/IDBFactoryBackendImpl.h13
-rw-r--r--WebCore/storage/IDBObjectStoreBackendImpl.cpp29
-rw-r--r--WebCore/storage/IDBObjectStoreBackendImpl.h3
-rw-r--r--WebCore/storage/IDBRequest.cpp14
-rw-r--r--WebCore/storage/IDBSQLiteDatabase.cpp48
-rw-r--r--WebCore/storage/IDBSQLiteDatabase.h62
-rw-r--r--WebCore/storage/IDBTransactionBackendImpl.cpp2
12 files changed, 248 insertions, 104 deletions
diff --git a/WebCore/storage/IDBDatabaseBackendImpl.cpp b/WebCore/storage/IDBDatabaseBackendImpl.cpp
index dc61e22..020ddb9 100644
--- a/WebCore/storage/IDBDatabaseBackendImpl.cpp
+++ b/WebCore/storage/IDBDatabaseBackendImpl.cpp
@@ -32,60 +32,65 @@
#include "DOMStringList.h"
#include "IDBDatabaseException.h"
#include "IDBObjectStoreBackendImpl.h"
+#include "IDBSQLiteDatabase.h"
#include "IDBTransactionBackendInterface.h"
#include "IDBTransactionCoordinator.h"
-#include "SQLiteDatabase.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
namespace WebCore {
-static bool extractMetaData(SQLiteDatabase* sqliteDatabase, const String& expectedName, String& foundVersion)
+static bool extractMetaData(SQLiteDatabase& sqliteDatabase, const String& name, String& foundVersion, int64& foundId)
{
- SQLiteStatement metaDataQuery(*sqliteDatabase, "SELECT name, 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());
+ SQLiteStatement databaseQuery(sqliteDatabase, "SELECT id, version FROM Databases WHERE name = ?");
+ if (databaseQuery.prepare() != SQLResultOk) {
ASSERT_NOT_REACHED();
+ return false;
}
- foundVersion = metaDataQuery.getColumnText(1);
+ databaseQuery.bindText(1, name);
+ if (databaseQuery.step() != SQLResultRow)
+ return false;
- if (metaDataQuery.step() == SQLResultRow) {
- LOG_ERROR("More than one row found in MetaData table");
- ASSERT_NOT_REACHED();
- }
+ foundId = databaseQuery.getColumnInt64(0);
+ foundVersion = databaseQuery.getColumnText(1);
+ if (databaseQuery.step() == SQLResultRow)
+ ASSERT_NOT_REACHED();
return true;
}
-static bool setMetaData(SQLiteDatabase* sqliteDatabase, const String& name, const String& description, const String& version)
+static bool setMetaData(SQLiteDatabase& sqliteDatabase, const String& name, const String& description, const String& version, int64_t& rowId)
{
- 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");
+ ASSERT(!name.isNull());
+ ASSERT(!description.isNull());
+ ASSERT(!version.isNull());
+
+ String sql = rowId != IDBDatabaseBackendImpl::InvalidId ? "UPDATE Databases SET name = ?, description = ?, version = ? WHERE id = ?"
+ : "INSERT INTO Databases (name, description, version) VALUES (?, ?, ?)";
+ SQLiteStatement query(sqliteDatabase, sql);
+ if (query.prepare() != SQLResultOk) {
+ ASSERT_NOT_REACHED();
return false;
}
- insert.bindText(1, name);
- insert.bindText(2, description);
- insert.bindText(3, version);
+ query.bindText(1, name);
+ query.bindText(2, description);
+ query.bindText(3, version);
+ if (rowId != IDBDatabaseBackendImpl::InvalidId)
+ query.bindInt64(4, rowId);
- if (insert.step() != SQLResultDone) {
- LOG_ERROR("Failed to insert row into MetaData for IndexedDB");
+ if (query.step() != SQLResultDone)
return false;
- }
+
+ if (rowId == IDBDatabaseBackendImpl::InvalidId)
+ rowId = sqliteDatabase.lastInsertRowID();
return true;
}
-IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> sqliteDatabase, IDBTransactionCoordinator* coordinator)
+IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, IDBSQLiteDatabase* sqliteDatabase, IDBTransactionCoordinator* coordinator)
: m_sqliteDatabase(sqliteDatabase)
+ , m_id(InvalidId)
, m_name(name)
, m_description(description)
, m_version("")
@@ -94,9 +99,10 @@ IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String&
ASSERT(!m_name.isNull());
ASSERT(!m_description.isNull());
- extractMetaData(m_sqliteDatabase.get(), m_name, m_version);
- setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version);
-
+ bool success = extractMetaData(m_sqliteDatabase->db(), m_name, m_version, m_id);
+ ASSERT_UNUSED(success, success == (m_id != InvalidId));
+ if (!setMetaData(m_sqliteDatabase->db(), m_name, m_description, m_version, m_id))
+ ASSERT_NOT_REACHED(); // FIXME: Need better error handling.
loadObjectStores();
}
@@ -110,7 +116,12 @@ void IDBDatabaseBackendImpl::setDescription(const String& description)
return;
m_description = description;
- setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version);
+ setMetaData(m_sqliteDatabase->db(), m_name, m_description, m_version, m_id);
+}
+
+SQLiteDatabase& IDBDatabaseBackendImpl::sqliteDatabase() const
+{
+ return m_sqliteDatabase->db();
}
PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStores() const
@@ -144,7 +155,7 @@ PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObject
void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
- SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement) VALUES (?, ?, ?)");
+ SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement, databaseId) VALUES (?, ?, ?, ?)");
if (insert.prepare() != SQLResultOk) {
transaction->abort();
return;
@@ -152,6 +163,7 @@ void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*,
insert.bindText(1, objectStore->name());
insert.bindText(2, objectStore->keyPath());
insert.bindInt(3, static_cast<int>(objectStore->autoIncrement()));
+ insert.bindInt64(4, database->id());
if (insert.step() != SQLResultDone) {
transaction->abort();
return;
@@ -217,8 +229,9 @@ void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCal
void IDBDatabaseBackendImpl::setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, const String& version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
+ int64_t databaseId = database->id();
database->m_version = version;
- if (!setMetaData(database->m_sqliteDatabase.get(), database->m_name, database->m_description, database->m_version)) {
+ if (!setMetaData(database->m_sqliteDatabase->db(), database->m_name, database->m_description, database->m_version, databaseId)) {
// FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
transaction->abort();
@@ -240,10 +253,12 @@ void IDBDatabaseBackendImpl::close()
void IDBDatabaseBackendImpl::loadObjectStores()
{
- SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores");
+ SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?");
bool ok = objectStoresQuery.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ objectStoresQuery.bindInt64(1, m_id);
+
while (objectStoresQuery.step() == SQLResultRow) {
int64_t id = objectStoresQuery.getColumnInt64(0);
String name = objectStoresQuery.getColumnText(1);
diff --git a/WebCore/storage/IDBDatabaseBackendImpl.h b/WebCore/storage/IDBDatabaseBackendImpl.h
index bb6429c..53e1a5f 100644
--- a/WebCore/storage/IDBDatabaseBackendImpl.h
+++ b/WebCore/storage/IDBDatabaseBackendImpl.h
@@ -36,19 +36,23 @@
namespace WebCore {
class IDBObjectStoreBackendImpl;
+class IDBSQLiteDatabase;
class IDBTransactionCoordinator;
class SQLiteDatabase;
class IDBDatabaseBackendImpl : public IDBDatabaseBackendInterface {
public:
- static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator* coordinator)
+ static PassRefPtr<IDBDatabaseBackendImpl> create(const String& name, const String& description, IDBSQLiteDatabase* 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(); }
+ SQLiteDatabase& sqliteDatabase() const;
+
+ static const int64_t InvalidId = 0;
+ int64_t id() const { return m_id; }
virtual String name() const { return m_name; }
virtual String description() const { return m_description; }
@@ -65,7 +69,7 @@ public:
IDBTransactionCoordinator* transactionCoordinator() const { return m_transactionCoordinator.get(); }
private:
- IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> database, IDBTransactionCoordinator*);
+ IDBDatabaseBackendImpl(const String& name, const String& description, IDBSQLiteDatabase* database, IDBTransactionCoordinator*);
void loadObjectStores();
@@ -78,7 +82,8 @@ private:
static void addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
static void resetVersion(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version);
- OwnPtr<SQLiteDatabase> m_sqliteDatabase;
+ RefPtr<IDBSQLiteDatabase> m_sqliteDatabase;
+ int64 m_id;
String m_name;
String m_description;
String m_version;
diff --git a/WebCore/storage/IDBDatabaseException.h b/WebCore/storage/IDBDatabaseException.h
index 251cfc9..945773c 100644
--- a/WebCore/storage/IDBDatabaseException.h
+++ b/WebCore/storage/IDBDatabaseException.h
@@ -42,9 +42,8 @@ public:
}
~IDBDatabaseException() { }
- // Keep in sync with what's in the .idl file.
enum ErrorCode {
- UNKNOWN_ERR = 0,
+ UNKNOWN_ERR = 1,
NON_TRANSIENT_ERR = 1,
NOT_FOUND_ERR = 2,
CONSTRAINT_ERR = 3,
diff --git a/WebCore/storage/IDBDatabaseException.idl b/WebCore/storage/IDBDatabaseException.idl
index 88e6e7e..1f15fc0 100644
--- a/WebCore/storage/IDBDatabaseException.idl
+++ b/WebCore/storage/IDBDatabaseException.idl
@@ -28,7 +28,8 @@ module storage {
interface [
Conditional=INDEXED_DATABASE
] IDBDatabaseException {
- const unsigned short UNKNOWN_ERR = 0;
+ // FIXME: These error codes conflict with others.
+ const unsigned short UNKNOWN_ERR = 1;
const unsigned short NON_TRANSIENT_ERR = 1;
const unsigned short NOT_FOUND_ERR = 2;
const unsigned short CONSTRAINT_ERR = 3;
diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp
index c18294d..1905c0c 100644
--- a/WebCore/storage/IDBFactoryBackendImpl.cpp
+++ b/WebCore/storage/IDBFactoryBackendImpl.cpp
@@ -33,8 +33,8 @@
#include "FileSystem.h"
#include "IDBDatabaseBackendImpl.h"
#include "IDBDatabaseException.h"
+#include "IDBSQLiteDatabase.h"
#include "IDBTransactionCoordinator.h"
-#include "SQLiteDatabase.h"
#include "SecurityOrigin.h"
#include <wtf/Threading.h>
#include <wtf/UnusedParam.h>
@@ -52,7 +52,13 @@ IDBFactoryBackendImpl::~IDBFactoryBackendImpl()
{
}
-static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name, const String& pathBase, int64_t maximumSize)
+void IDBFactoryBackendImpl::removeSQLiteDatabase(const String& filePath)
+{
+ ASSERT(m_sqliteDatabaseMap.contains(filePath));
+ m_sqliteDatabaseMap.remove(filePath);
+}
+
+static PassRefPtr<IDBSQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, const String& pathBase, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory)
{
String path = ":memory:";
if (!pathBase.isEmpty()) {
@@ -62,54 +68,46 @@ static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOri
return 0;
}
- path = pathByAppendingComponent(pathBase, IDBFactoryBackendImpl::databaseFileName(name, securityOrigin));
+ path = pathByAppendingComponent(pathBase, IDBFactoryBackendImpl::databaseFileName(securityOrigin));
}
- OwnPtr<SQLiteDatabase> sqliteDatabase = adoptPtr(new SQLiteDatabase());
- if (!sqliteDatabase->open(path)) {
+ RefPtr<IDBSQLiteDatabase> sqliteDatabase = IDBSQLiteDatabase::create(fileIdentifier, factory);
+ if (!sqliteDatabase->db().open(path)) {
// FIXME: Is there any other thing we could possibly do to recover at this point? If so, do it rather than just erroring out.
LOG_ERROR("Failed to open database file %s for IndexedDB", path.utf8().data());
return 0;
}
- sqliteDatabase->setMaximumSize(maximumSize);
+ // FIXME: Error checking?
+ sqliteDatabase->db().setMaximumSize(maximumSize);
+ sqliteDatabase->db().turnOnIncrementalAutoVacuum();
+
return sqliteDatabase.release();
}
-static bool createTables(SQLiteDatabase* sqliteDatabase)
+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)",
+ "CREATE TABLE IF NOT EXISTS Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)",
+ "CREATE UNIQUE INDEX IF NOT EXISTS Databases_name ON Databases(name)",
- "DROP TABLE IF EXISTS ObjectStores",
- "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE, keyPath TEXT, doAutoIncrement INTEGER NOT NULL)",
- "DROP INDEX IF EXISTS ObjectStores_name",
- "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_name ON ObjectStores(name)",
+ "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFERENCES Databases(id))",
+ "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_composit ON ObjectStores(databaseId, name)",
- "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 UNIQUE, keyPath TEXT, isUnique INTEGER NOT NULL)",
- "DROP INDEX IF EXISTS Indexes_composit",
+ "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)",
"CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectStoreId, name)",
- "DROP TABLE IF EXISTS ObjectStoreData",
- "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT UNIQUE, keyDate INTEGER UNIQUE, keyNumber INTEGER UNIQUE, value TEXT NOT NULL)",
- "DROP INDEX IF EXISTS ObjectStoreData_composit",
+ "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)",
"CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
- "DROP TABLE IF EXISTS IndexData",
"CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
- "DROP INDEX IF EXISTS IndexData_composit",
"CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
- "DROP INDEX IF EXISTS IndexData_objectStoreDataId",
"CREATE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
- "DROP INDEX IF EXISTS IndexData_indexId",
"CREATE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)"
};
for (size_t i = 0; i < arraysize(commands); ++i) {
- if (!sqliteDatabase->executeCommand(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;
@@ -120,7 +118,9 @@ static bool createTables(SQLiteDatabase* sqliteDatabase)
void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize)
{
- IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(name);
+ String fileIdentifier = securityOrigin->databaseIdentifier();
+ String uniqueIdentifier = fileIdentifier + "@" + name;
+ IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
if (it != m_databaseBackendMap.end()) {
if (!description.isNull())
it->second->setDescription(description); // The description may have changed.
@@ -130,22 +130,29 @@ void IDBFactoryBackendImpl::open(const String& name, const String& description,
// FIXME: Everything from now on should be done on another thread.
- OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name, dataDir, maximumSize);
- if (!sqliteDatabase || !createTables(sqliteDatabase.get())) {
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
- return;
+ RefPtr<IDBSQLiteDatabase> sqliteDatabase;
+ SQLiteDatabaseMap::iterator it2 = m_sqliteDatabaseMap.find(fileIdentifier);
+ if (it2 != m_sqliteDatabaseMap.end())
+ sqliteDatabase = it2->second;
+ else {
+ sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maximumSize, fileIdentifier, this);
+
+ if (!sqliteDatabase || !createTables(sqliteDatabase->db())) {
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+ return;
+ }
+ m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get());
}
- RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, description, sqliteDatabase.release(), m_transactionCoordinator.get());
+ RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, description, sqliteDatabase.get(), m_transactionCoordinator.get());
callbacks->onSuccess(databaseBackend.get());
- m_databaseBackendMap.set(name, databaseBackend.release());
+ m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.release());
}
-String IDBFactoryBackendImpl::databaseFileName(const String& name, SecurityOrigin* securityOrigin)
+String IDBFactoryBackendImpl::databaseFileName(SecurityOrigin* securityOrigin)
{
String databaseIdentifier = securityOrigin->databaseIdentifier();
- String santizedName = encodeForFileName(name);
- return databaseIdentifier + "@" + santizedName + ".indexeddb";
+ return databaseIdentifier + ".indexeddb";
}
} // namespace WebCore
diff --git a/WebCore/storage/IDBFactoryBackendImpl.h b/WebCore/storage/IDBFactoryBackendImpl.h
index 211b7fa..381c402 100644
--- a/WebCore/storage/IDBFactoryBackendImpl.h
+++ b/WebCore/storage/IDBFactoryBackendImpl.h
@@ -39,6 +39,7 @@ namespace WebCore {
class DOMStringList;
class IDBDatabaseBackendImpl;
+class IDBSQLiteDatabase;
class IDBTransactionCoordinator;
class IDBFactoryBackendImpl : public IDBFactoryBackendInterface {
@@ -49,18 +50,26 @@ public:
}
virtual ~IDBFactoryBackendImpl();
+ // IDBSQLiteDatabase's lifetime may be shorter than ours, so we need notification when it dies.
+ void removeSQLiteDatabase(const String& filePath);
+
virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize);
- static String databaseFileName(const String& name, SecurityOrigin*);
+ static String databaseFileName(SecurityOrigin*);
private:
IDBFactoryBackendImpl();
+ // FIXME: Just hold a weak pointer.
typedef HashMap<String, RefPtr<IDBDatabaseBackendImpl> > IDBDatabaseBackendMap;
IDBDatabaseBackendMap m_databaseBackendMap;
+
+ typedef HashMap<String, IDBSQLiteDatabase*> SQLiteDatabaseMap;
+ SQLiteDatabaseMap m_sqliteDatabaseMap;
+
RefPtr<IDBTransactionCoordinator> m_transactionCoordinator;
- // We only create one instance of this class at a time.
+ // Only one instance of the factory should exist at any given time.
static IDBFactoryBackendImpl* idbFactoryBackendImpl;
};
diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
index f3aee91..4892556 100644
--- a/WebCore/storage/IDBObjectStoreBackendImpl.cpp
+++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
@@ -131,25 +131,25 @@ static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, cons
return keys[0].release();
}
-static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t* dataRowId)
+static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t& dataRowId)
{
- String sql = *dataRowId != -1 ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?"
- : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)";
+ String sql = dataRowId != IDBObjectStoreBackendImpl::InvalidId ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?"
+ : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)";
SQLiteStatement query(db, sql);
if (query.prepare() != SQLResultOk)
return false;
key->bindWithNulls(query, 1);
query.bindText(4, value->toWireString());
- if (*dataRowId != -1)
- query.bindInt(5, *dataRowId);
+ if (dataRowId != IDBDatabaseBackendImpl::InvalidId)
+ query.bindInt64(5, dataRowId);
else
query.bindInt64(5, objectStoreId);
if (query.step() != SQLResultDone)
return false;
- if (*dataRowId == -1)
- *dataRowId = db.lastInsertRowID();
+ if (dataRowId == IDBDatabaseBackendImpl::InvalidId)
+ dataRowId = db.lastInsertRowID();
return true;
}
@@ -238,8 +238,8 @@ void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<
// Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
- int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : -1;
- if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), &dataRowId)) {
+ int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId;
+ if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), dataRowId)) {
// FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
transaction->abort();
@@ -394,11 +394,14 @@ void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, uns
void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
+ bool leftBound = range && (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE);
+ bool rightBound = range && (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE);
+
// Several files depend on this order of selects.
String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE ";
- if (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE)
+ if (leftBound)
sql += range->left()->leftCursorWhereFragment(range->leftWhereClauseComparisonOperator());
- if (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE)
+ if (rightBound)
sql += range->right()->rightCursorWhereFragment(range->rightWhereClauseComparisonOperator());
sql += "objectStoreId = ? ORDER BY ";
@@ -413,9 +416,9 @@ void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, Pass
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
int currentColumn = 1;
- if (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE)
+ if (leftBound)
currentColumn += range->left()->bind(*query, currentColumn);
- if (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE)
+ if (rightBound)
currentColumn += range->right()->bind(*query, currentColumn);
query->bindInt64(currentColumn, objectStore->id());
diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.h b/WebCore/storage/IDBObjectStoreBackendImpl.h
index 09223b1..60e011f 100644
--- a/WebCore/storage/IDBObjectStoreBackendImpl.h
+++ b/WebCore/storage/IDBObjectStoreBackendImpl.h
@@ -52,6 +52,7 @@ public:
}
virtual ~IDBObjectStoreBackendImpl();
+ static const int64_t InvalidId = 0;
int64_t id() const
{
ASSERT(m_id != InvalidId);
@@ -94,8 +95,6 @@ private:
static void removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
static void addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
- static const int64_t InvalidId = 0;
-
RefPtr<IDBDatabaseBackendImpl> m_database;
int64_t m_id;
diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp
index c67e379..cbd635c 100644
--- a/WebCore/storage/IDBRequest.cpp
+++ b/WebCore/storage/IDBRequest.cpp
@@ -59,15 +59,6 @@ IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> sourc
IDBRequest::~IDBRequest()
{
- // The transaction pointer is used to notify the transaction once the JS events were
- // dispatched by this request object. If no new tasks were added by the event JS callbacks,
- // the transaction can commit. Otherwise, it can continue executing the new tasks.
- // It is important to guarantee that the transaction is notified after the events are
- // dispatched, as the transaction cannot commit or execute new tasks in the absence
- // of these notifications. We clear the transaction pointer once the events have dispatched,
- // so having a non-zero pointer at IDBRequest destruction time shows that the events have not
- // yet fired and there is a transaction waiting to be notified. This is an error.
- ASSERT(!m_transaction);
}
bool IDBRequest::resetReadyState(IDBTransactionBackendInterface* transaction)
@@ -159,6 +150,7 @@ void IDBRequest::timerFired(Timer<IDBRequest>*)
{
ASSERT(m_selfRef);
ASSERT(m_pendingEvents.size());
+ // FIXME: We should handle the stop event and stop any timers when we see it. We can then assert here that scriptExecutionContext is non-null.
// We need to keep self-referencing ourself, otherwise it's possible we'll be deleted.
// But in some cases, suspend() could be called while we're dispatching an event, so we
@@ -172,6 +164,10 @@ void IDBRequest::timerFired(Timer<IDBRequest>*)
Vector<PendingEvent> pendingEvents;
pendingEvents.swap(m_pendingEvents);
for (size_t i = 0; i < pendingEvents.size(); ++i) {
+ // It's possible we've navigated in which case we'll crash.
+ if (!scriptExecutionContext())
+ return;
+
if (pendingEvents[i].m_error) {
ASSERT(!pendingEvents[i].m_result);
dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvents[i].m_error));
diff --git a/WebCore/storage/IDBSQLiteDatabase.cpp b/WebCore/storage/IDBSQLiteDatabase.cpp
new file mode 100644
index 0000000..e881917
--- /dev/null
+++ b/WebCore/storage/IDBSQLiteDatabase.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBSQLiteDatabase.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBFactoryBackendImpl.h"
+
+namespace WebCore {
+
+IDBSQLiteDatabase::IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory)
+ : m_identifier(identifier)
+ , m_factory(factory)
+{
+}
+
+IDBSQLiteDatabase::~IDBSQLiteDatabase()
+{
+ m_factory->removeSQLiteDatabase(m_identifier);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBSQLiteDatabase.h b/WebCore/storage/IDBSQLiteDatabase.h
new file mode 100644
index 0000000..0556506
--- /dev/null
+++ b/WebCore/storage/IDBSQLiteDatabase.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBSQLiteDatabase_h
+#define IDBSQLiteDatabase_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "SQLiteDatabase.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBFactoryBackendImpl;
+
+class IDBSQLiteDatabase : public RefCounted<IDBSQLiteDatabase> {
+public:
+ static PassRefPtr<IDBSQLiteDatabase> create(String identifier, IDBFactoryBackendImpl* factory)
+ {
+ return adoptRef(new IDBSQLiteDatabase(identifier, factory));
+ }
+ ~IDBSQLiteDatabase();
+
+ SQLiteDatabase& db() { return m_db; }
+
+private:
+ IDBSQLiteDatabase(String identifier, IDBFactoryBackendImpl* factory);
+
+ SQLiteDatabase m_db;
+ String m_identifier;
+ RefPtr<IDBFactoryBackendImpl> m_factory;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // IDBSQLiteDatabase_h
diff --git a/WebCore/storage/IDBTransactionBackendImpl.cpp b/WebCore/storage/IDBTransactionBackendImpl.cpp
index 5016a3f..2b1f732 100644
--- a/WebCore/storage/IDBTransactionBackendImpl.cpp
+++ b/WebCore/storage/IDBTransactionBackendImpl.cpp
@@ -147,7 +147,7 @@ void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*
TaskQueue queue;
queue.swap(m_taskQueue);
- while (!queue.isEmpty()) {
+ while (!queue.isEmpty() && m_state != Finished) {
OwnPtr<ScriptExecutionContext::Task> task(queue.first().release());
queue.removeFirst();
m_pendingEvents++;