LayoutTests/ChangeLog

 12010-08-24 Jeremy Orlow <jorlow@chromium.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 IndexedDB needs to manually delete all objectStore data and indexes
 6 https://bugs.webkit.org/show_bug.cgi?id=44522
 7
 8 * storage/indexeddb/objectstore-removeobjectstore-expected.txt: Added.
 9 * storage/indexeddb/objectstore-removeobjectstore.html: Added.
 10 * storage/indexeddb/resources/shared.js:
 11 (unexpectedSuccessCallback):
 12
1132010-08-19 Jeremy Orlow <jorlow@chromium.org>
214
315 Reviewed by Steve Block.

LayoutTests/storage/indexeddb/objectstore-removeobjectstore-expected.txt

 1Test IndexedDB's IDBObjectStore.removeObjectStore().
 2
 3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 4
 5
 6indexedDB.open('name', 'description')
 7PASS 'onsuccess' in result is true
 8PASS 'onerror' in result is true
 9PASS 'abort' in result is true
 10PASS 'readyState' in result is true
 11An event should fire shortly...
 12
 13Success event fired:
 14PASS 'result' in event is true
 15PASS 'code' in event is false
 16PASS 'message' in event is false
 17PASS 'source' in event is true
 18PASS event.source != null is true
 19PASS 'onsuccess' in event.target is true
 20PASS 'onerror' in event.target is true
 21PASS 'abort' in event.target is true
 22PASS 'readyState' in event.target is true
 23PASS event.target.readyState is event.target.DONE
 24
 25db = event.result
 26db.createObjectStore('storeName', null)
 27PASS 'onsuccess' in result is true
 28PASS 'onerror' in result is true
 29PASS 'abort' in result is true
 30PASS 'readyState' in result is true
 31An event should fire shortly...
 32
 33Success event fired:
 34PASS 'result' in event is true
 35PASS 'code' in event is false
 36PASS 'message' in event is false
 37PASS 'source' in event is true
 38PASS event.source != null is true
 39PASS 'onsuccess' in event.target is true
 40PASS 'onerror' in event.target is true
 41PASS 'abort' in event.target is true
 42PASS 'readyState' in event.target is true
 43PASS event.target.readyState is event.target.DONE
 44
 45event.result.add('value', 'key')
 46PASS 'onsuccess' in result is true
 47PASS 'onerror' in result is true
 48PASS 'abort' in result is true
 49PASS 'readyState' in result is true
 50An event should fire shortly...
 51
 52Success event fired:
 53PASS 'result' in event is true
 54PASS 'code' in event is false
 55PASS 'message' in event is false
 56PASS 'source' in event is true
 57PASS event.source != null is true
 58PASS 'onsuccess' in event.target is true
 59PASS 'onerror' in event.target is true
 60PASS 'abort' in event.target is true
 61PASS 'readyState' in event.target is true
 62PASS event.target.readyState is event.target.DONE
 63
 64event.source.get('key')
 65PASS 'onsuccess' in result is true
 66PASS 'onerror' in result is true
 67PASS 'abort' in result is true
 68PASS 'readyState' in result is true
 69An event should fire shortly...
 70
 71Success event fired:
 72PASS 'result' in event is true
 73PASS 'code' in event is false
 74PASS 'message' in event is false
 75PASS 'source' in event is true
 76PASS event.source != null is true
 77PASS 'onsuccess' in event.target is true
 78PASS 'onerror' in event.target is true
 79PASS 'abort' in event.target is true
 80PASS 'readyState' in event.target is true
 81PASS event.target.readyState is event.target.DONE
 82
 83PASS event.result is "value"
 84event.source.createIndex('indexName', '')
 85PASS 'onsuccess' in result is true
 86PASS 'onerror' in result is true
 87PASS 'abort' in result is true
 88PASS 'readyState' in result is true
 89An event should fire shortly...
 90
 91Success event fired:
 92PASS 'result' in event is true
 93PASS 'code' in event is false
 94PASS 'message' in event is false
 95PASS 'source' in event is true
 96PASS event.source != null is true
 97PASS 'onsuccess' in event.target is true
 98PASS 'onerror' in event.target is true
 99PASS 'abort' in event.target is true
 100PASS 'readyState' in event.target is true
 101PASS event.target.readyState is event.target.DONE
 102
 103PASS event.source.indexNames.contains('indexName') is true
 104db.removeObjectStore('storeName')
 105PASS 'onsuccess' in result is true
 106PASS 'onerror' in result is true
 107PASS 'abort' in result is true
 108PASS 'readyState' in result is true
 109An event should fire shortly...
 110
 111Success event fired:
 112PASS 'result' in event is true
 113PASS 'code' in event is false
 114PASS 'message' in event is false
 115PASS 'source' in event is true
 116PASS event.source != null is true
 117PASS 'onsuccess' in event.target is true
 118PASS 'onerror' in event.target is true
 119PASS 'abort' in event.target is true
 120PASS 'readyState' in event.target is true
 121PASS event.target.readyState is event.target.DONE
 122
 123db.createObjectStore('storeName', null)
 124PASS 'onsuccess' in result is true
 125PASS 'onerror' in result is true
 126PASS 'abort' in result is true
 127PASS 'readyState' in result is true
 128An event should fire shortly...
 129
 130Success event fired:
 131PASS 'result' in event is true
 132PASS 'code' in event is false
 133PASS 'message' in event is false
 134PASS 'source' in event is true
 135PASS event.source != null is true
 136PASS 'onsuccess' in event.target is true
 137PASS 'onerror' in event.target is true
 138PASS 'abort' in event.target is true
 139PASS 'readyState' in event.target is true
 140PASS event.target.readyState is event.target.DONE
 141
 142event.result.get('key')
 143PASS 'onsuccess' in result is true
 144PASS 'onerror' in result is true
 145PASS 'abort' in result is true
 146PASS 'readyState' in result is true
 147An event should fire shortly...
 148
 149Error event fired:
 150PASS 'result' in event is false
 151PASS 'code' in event is true
 152PASS 'message' in event is true
 153PASS 'source' in event is true
 154PASS event.source != null is true
 155PASS 'onsuccess' in event.target is true
 156PASS 'onerror' in event.target is true
 157PASS 'abort' in event.target is true
 158PASS 'readyState' in event.target is true
 159PASS event.target.readyState is event.target.DONE
 160
 161PASS event.code is 2
 162PASS event.source.indexNames.contains('indexName') is false
 163PASS successfullyParsed is true
 164
 165TEST COMPLETE
 166

LayoutTests/storage/indexeddb/objectstore-removeobjectstore.html

 1<html>
 2<head>
 3<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
 4<script src="../../fast/js/resources/js-test-pre.js"></script>
 5<script src="../../fast/js/resources/js-test-post-function.js"></script>
 6<script src="resources/shared.js"></script>
 7</head>
 8<body>
 9<p id="description"></p>
 10<div id="console"></div>
 11<script>
 12
 13description("Test IndexedDB's IDBObjectStore.removeObjectStore().");
 14if (window.layoutTestController)
 15 layoutTestController.waitUntilDone();
 16
 17function test()
 18{
 19 result = evalAndLog("indexedDB.open('name', 'description')");
 20 verifyResult(result);
 21 result.onsuccess = createObjectStore;
 22 result.onerror = unexpectedErrorCallback;
 23}
 24
 25function createObjectStore()
 26{
 27 verifySuccessEvent(event);
 28 db = evalAndLog("db = event.result");
 29
 30 deleteAllObjectStores(db);
 31
 32 result = evalAndLog("db.createObjectStore('storeName', null)");
 33 verifyResult(result);
 34 result.onsuccess = addValue;
 35 result.onerror = unexpectedErrorCallback;
 36}
 37
 38function addValue()
 39{
 40 verifySuccessEvent(event);
 41
 42 result = evalAndLog("event.result.add('value', 'key')");
 43 verifyResult(result);
 44 result.onsuccess = getValue;
 45 result.onerror = unexpectedErrorCallback;
 46}
 47
 48function getValue()
 49{
 50 verifySuccessEvent(event);
 51
 52 result = evalAndLog("event.source.get('key')");
 53 verifyResult(result);
 54 result.onsuccess = addIndex;
 55 result.onerror = unexpectedErrorCallback;
 56}
 57
 58function addIndex()
 59{
 60 verifySuccessEvent(event);
 61 shouldBeEqualToString("event.result", "value");
 62
 63 result = evalAndLog("event.source.createIndex('indexName', '')");
 64 verifyResult(result);
 65 result.onsuccess = removeObjectStore;
 66 result.onerror = unexpectedErrorCallback;
 67}
 68
 69function removeObjectStore()
 70{
 71 verifySuccessEvent(event);
 72 shouldBeTrue("event.source.indexNames.contains('indexName')");
 73
 74 result = evalAndLog("db.removeObjectStore('storeName')");
 75 verifyResult(result);
 76 result.onsuccess = createObjectStoreAgain;
 77 result.onerror = unexpectedErrorCallback;
 78}
 79
 80function createObjectStoreAgain()
 81{
 82 verifySuccessEvent(event);
 83
 84 result = evalAndLog("db.createObjectStore('storeName', null)");
 85 verifyResult(result);
 86 result.onsuccess = getValueAgain;
 87 result.onerror = unexpectedErrorCallback;
 88}
 89
 90function getValueAgain()
 91{
 92 verifySuccessEvent(event);
 93
 94 result = evalAndLog("event.result.get('key')");
 95 verifyResult(result);
 96 result.onsuccess = unexpectedSuccessCallback;
 97 result.onerror = verifyError;
 98}
 99
 100function verifyError()
 101{
 102 verifyErrorEvent(event);
 103 // FIXME: Should just be IDBDatabaseException.NOT_FOUND_ERR but that doesn't work yet.
 104 shouldBe("event.code", "2");
 105 shouldBeFalse("event.source.indexNames.contains('indexName')");
 106
 107 done();
 108}
 109
 110test();
 111
 112var successfullyParsed = true;
 113</script>
 114</body>
 115</html>

LayoutTests/storage/indexeddb/resources/shared.js

@@function verifyResult(result)
5151 debug("");
5252}
5353
 54function unexpectedSuccessCallback()
 55{
 56 testFailed("Success function called unexpectedly.");
 57 debug("");
 58 verifySuccessEvent(event);
 59 done();
 60}
 61
5462function unexpectedErrorCallback()
5563{
5664 testFailed("Error function called unexpectedly: (" + event.code + ") " + event.message);

WebCore/ChangeLog

 12010-08-24 Jeremy Orlow <jorlow@chromium.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 IndexedDB needs to manually delete all objectStore data and indexes
 6 https://bugs.webkit.org/show_bug.cgi?id=44522
 7
 8 Apparently it's only newer versions of SQLite that handle cascade
 9 delete. The rest silently fail. So do it manually.
 10
 11 Test: storage/indexeddb/objectstore-removeobjectstore.html
 12
 13 * storage/IDBDatabaseBackendImpl.cpp:
 14 (WebCore::IDBDatabaseBackendImpl::createObjectStore):
 15 (WebCore::doDelete):
 16 (WebCore::IDBDatabaseBackendImpl::removeObjectStore):
 17 * storage/IDBDatabaseBackendImpl.h:
 18 * storage/IDBFactoryBackendImpl.cpp:
 19 (WebCore::createTables):
 20 * storage/IDBObjectStoreBackendImpl.cpp:
 21 (WebCore::IDBObjectStoreBackendImpl::removeIndex):
 22 * storage/IDBObjectStoreBackendImpl.h:
 23 (WebCore::IDBObjectStoreBackendImpl::create):
 24 (WebCore::IDBObjectStoreBackendImpl::id):
 25
1262010-08-19 Jeremy Orlow <jorlow@chromium.org>
227
328 Reviewed by Steve Block.

WebCore/storage/IDBDatabaseBackendImpl.cpp

3232#include "IDBTransactionCoordinator.h"
3333#include "SQLiteDatabase.h"
3434#include "SQLiteStatement.h"
 35#include "SQLiteTransaction.h"
3536
3637#if ENABLE(INDEXED_DATABASE)
3738

@@void IDBDatabaseBackendImpl::createObjectStore(const String& name, const String&
141142 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
142143 int64_t id = sqliteDatabase().lastInsertRowID();
143144
144  RefPtr<IDBObjectStoreBackendInterface> objectStore = IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement);
 145 RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement);
145146 ASSERT(objectStore->name() == name);
146147 m_objectStores.set(name, objectStore);
147  callbacks->onSuccess(objectStore.release());
 148 callbacks->onSuccess(objectStore.get());
148149}
149150
150151PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name, unsigned short mode)

@@PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(c
154155 return m_objectStores.get(name);
155156}
156157
 158static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
 159{
 160 SQLiteStatement deleteQuery(db, sql);
 161 bool ok = deleteQuery.prepare() == SQLResultOk;
 162 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
 163 deleteQuery.bindInt64(1, id);
 164 ok = deleteQuery.step() == SQLResultDone;
 165 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
 166}
 167
157168void IDBDatabaseBackendImpl::removeObjectStore(const String& name, PassRefPtr<IDBCallbacks> callbacks)
158169{
159  if (!m_objectStores.contains(name)) {
 170 RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name);
 171 if (!objectStore) {
160172 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "No objectStore with that name exists."));
161173 return;
162174 }
163175
164  SQLiteStatement deleteQuery(sqliteDatabase(), "DELETE FROM ObjectStores WHERE name = ?");
165  bool ok = deleteQuery.prepare() == SQLResultOk;
166  ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
167  deleteQuery.bindText(1, name);
168  ok = deleteQuery.step() == SQLResultDone;
169  ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
 176 SQLiteTransaction transaction(sqliteDatabase());
 177 transaction.begin();
 178 doDelete(sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id());
 179 doDelete(sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id());
 180 doDelete(sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id());
 181 // FIXME: Delete index data as well.
 182 transaction.commit();
170183
171184 m_objectStores.remove(name);
172185 callbacks->onSuccess();

WebCore/storage/IDBDatabaseBackendImpl.h

3535
3636namespace WebCore {
3737
 38class IDBObjectStoreBackendImpl;
3839class IDBTransactionCoordinator;
3940class SQLiteDatabase;
4041

@@private:
6970 String m_description;
7071 String m_version;
7172
72  typedef HashMap<String, RefPtr<IDBObjectStoreBackendInterface> > ObjectStoreMap;
 73 typedef HashMap<String, RefPtr<IDBObjectStoreBackendImpl> > ObjectStoreMap;
7374 ObjectStoreMap m_objectStores;
7475
7576 RefPtr<IDBTransactionCoordinator> m_transactionCoordinator;

WebCore/storage/IDBFactoryBackendImpl.cpp

@@static bool createTables(SQLiteDatabase* sqliteDatabase)
8888 "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_name ON ObjectStores(name)",
8989
9090 "DROP TABLE IF EXISTS Indexes",
91  "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id) ON DELETE CASCADE, name TEXT NOT NULL, keyPath TEXT, isUnique INTEGER NOT NULL)",
 91 "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)",
9292 "DROP INDEX IF EXISTS Indexes_composit",
9393 "CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectStoreId, name)",
9494
9595 "DROP TABLE IF EXISTS ObjectStoreData",
96  "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id) ON DELETE CASCADE, keyString TEXT, keyDate INTEGER, keyNumber INTEGER, value TEXT NOT NULL)",
 96 "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)",
9797 "DROP INDEX IF EXISTS ObjectStoreData_composit",
9898 "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)"
9999 };

WebCore/storage/IDBObjectStoreBackendImpl.cpp

@@void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCa
250250 ok = deleteQuery.step() == SQLResultDone;
251251 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
252252
 253 // FIXME: Delete index data as well.
 254
253255 m_indexes.remove(name);
254256 callbacks->onSuccess();
255257}

WebCore/storage/IDBObjectStoreBackendImpl.h

@@class SQLiteDatabase;
3939
4040class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface {
4141public:
42  static PassRefPtr<IDBObjectStoreBackendInterface> create(IDBDatabaseBackendImpl* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
 42 static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBDatabaseBackendImpl* database, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
4343 {
4444 return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement));
4545 }
4646 ~IDBObjectStoreBackendImpl();
4747
 48 int64_t id() const { return m_id; }
4849 String name() const { return m_name; }
4950 String keyPath() const { return m_keyPath; }
5051 PassRefPtr<DOMStringList> indexNames() const;