e6ce83c35b38c04eceafa78a9aad55ff80afb7b1
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBObjectStoreBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBObjectStoreBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBackingStore.h"
32 #include "IDBBindingUtilities.h"
33 #include "IDBCallbacks.h"
34 #include "IDBCursorBackendImpl.h"
35 #include "IDBDatabaseBackendImpl.h"
36 #include "IDBDatabaseException.h"
37 #include "IDBIndexBackendImpl.h"
38 #include "IDBKey.h"
39 #include "IDBKeyPath.h"
40 #include "IDBKeyRange.h"
41 #include "IDBTracing.h"
42 #include "IDBTransactionBackendImpl.h"
43 #include <wtf/MathExtras.h>
44
45 namespace WebCore {
46
47 class IDBObjectStoreBackendImpl::CreateIndexOperation : public IDBTransactionBackendImpl::Operation {
48 public:
49     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
50     {
51         return adoptPtr(new CreateIndexOperation(objectStore, index));
52     }
53     virtual void perform(IDBTransactionBackendImpl*);
54 private:
55     CreateIndexOperation(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
56         : m_objectStore(objectStore)
57         , m_index(index)
58     {
59     }
60
61     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
62     RefPtr<IDBIndexBackendImpl> m_index;
63 };
64
65 class IDBObjectStoreBackendImpl::DeleteIndexOperation : public IDBTransactionBackendImpl::Operation {
66 public:
67     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
68     {
69         return adoptPtr(new DeleteIndexOperation(objectStore, index));
70     }
71     virtual void perform(IDBTransactionBackendImpl*);
72 private:
73     DeleteIndexOperation(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
74         : m_objectStore(objectStore)
75         , m_index(index)
76     {
77     }
78
79     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
80     RefPtr<IDBIndexBackendImpl> m_index;
81 };
82
83 class IDBObjectStoreBackendImpl::CreateIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
84 public:
85     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
86     {
87         return adoptPtr(new CreateIndexAbortOperation(objectStore, index));
88     }
89     virtual void perform(IDBTransactionBackendImpl*);
90 private:
91     CreateIndexAbortOperation(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
92         : m_objectStore(objectStore)
93         , m_index(index)
94     {
95     }
96
97     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
98     RefPtr<IDBIndexBackendImpl> m_index;
99 };
100
101 class IDBObjectStoreBackendImpl::DeleteIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
102 public:
103     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
104     {
105         return adoptPtr(new DeleteIndexAbortOperation(objectStore, index));
106     }
107     virtual void perform(IDBTransactionBackendImpl*);
108 private:
109     DeleteIndexAbortOperation(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
110         : m_objectStore(objectStore)
111         , m_index(index)
112     {
113     }
114
115     RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
116     RefPtr<IDBIndexBackendImpl> m_index;
117 };
118
119
120 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
121 {
122 }
123
124 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, const IDBObjectStoreMetadata& metadata)
125     : m_database(database)
126     , m_metadata(metadata)
127 {
128     loadIndexes();
129 }
130
131 IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
132 {
133     IDBObjectStoreMetadata metadata(m_metadata);
134     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
135         metadata.indexes.set(it->key, it->value->metadata());
136     return metadata;
137 }
138
139 bool IDBObjectStoreBackendImpl::IndexWriter::verifyIndexKeys(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, bool& canAddKeys, const IDBKey* primaryKey, String* errorMessage) const
140 {
141     canAddKeys = false;
142     for (size_t i = 0; i < m_indexKeys.size(); ++i) {
143         bool ok = addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId, (m_indexKeys)[i].get(), primaryKey, canAddKeys);
144         if (!ok)
145             return false;
146         if (!canAddKeys) {
147             if (errorMessage)
148                 *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.", m_indexMetadata.name.utf8().data());
149             return true;
150         }
151     }
152     canAddKeys = true;
153     return true;
154 }
155
156 void IDBObjectStoreBackendImpl::IndexWriter::writeIndexKeys(const IDBBackingStore::RecordIdentifier& recordIdentifier, IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId) const
157 {
158     int64_t indexId = m_indexMetadata.id;
159     for (size_t i = 0; i < m_indexKeys.size(); ++i) {
160         backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier);
161     }
162 }
163
164 bool IDBObjectStoreBackendImpl::IndexWriter::addingKeyAllowed(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey* indexKey, const IDBKey* primaryKey, bool& allowed) const
165 {
166     allowed = false;
167     if (!m_indexMetadata.unique) {
168         allowed = true;
169         return true;
170     }
171
172     RefPtr<IDBKey> foundPrimaryKey;
173     bool found = false;
174     bool ok = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey, found);
175     if (!ok)
176         return false;
177     if (!found || (primaryKey && foundPrimaryKey->isEqual(primaryKey)))
178         allowed = true;
179     return true;
180 }
181
182 bool IDBObjectStoreBackendImpl::makeIndexWriters(PassRefPtr<IDBTransactionBackendImpl> transaction, IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, PassRefPtr<IDBKey> primaryKey, bool keyWasGenerated, const Vector<int64_t>& indexIds, const Vector<IDBObjectStoreBackendInterface::IndexKeys>& indexKeys, Vector<OwnPtr<IndexWriter> >* indexWriters, String* errorMessage, bool& completed)
183 {
184     ASSERT(indexIds.size() == indexKeys.size());
185     completed = false;
186
187     HashMap<int64_t, IDBObjectStoreBackendInterface::IndexKeys> indexKeyMap;
188     for (size_t i = 0; i < indexIds.size(); ++i)
189         indexKeyMap.add(indexIds[i], indexKeys[i]);
190
191     for (IDBObjectStoreMetadata::IndexMap::const_iterator it = objectStore.indexes.begin(); it != objectStore.indexes.end(); ++it) {
192
193         const IDBIndexMetadata& index = it->value;
194
195         IDBObjectStoreBackendInterface::IndexKeys keys = indexKeyMap.get(it->key);
196         // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key.
197         if (keyWasGenerated && (index.keyPath == objectStore.keyPath))
198             keys.append(primaryKey);
199
200         OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index, keys)));
201         bool canAddKeys = false;
202         bool backingStoreSuccess = indexWriter->verifyIndexKeys(*backingStore, transaction->backingStoreTransaction(), databaseId, objectStore.id, index.id, canAddKeys, primaryKey.get(), errorMessage);
203         if (!backingStoreSuccess)
204             return false;
205         if (!canAddKeys)
206             return true;
207
208         indexWriters->append(indexWriter.release());
209     }
210
211     completed = true;
212     return true;
213 }
214
215 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
216 {
217     ASSERT_WITH_MESSAGE(!m_indexes.contains(id), "Indexes already contain '%s'", name.utf8().data());
218
219     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, IDBIndexMetadata(name, id, keyPath, unique, multiEntry));
220     ASSERT(index->name() == name);
221
222     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
223     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
224     ASSERT(id > m_metadata.maxIndexId);
225     m_metadata.maxIndexId = id;
226
227     if (!transaction->scheduleTask(CreateIndexOperation::create(this, index), CreateIndexAbortOperation::create(this, index))) {
228         ec = IDBDatabaseException::TransactionInactiveError;
229         return 0;
230     }
231
232     m_indexes.set(id, index);
233     return index.release();
234 }
235
236 void IDBObjectStoreBackendImpl::CreateIndexOperation::perform(IDBTransactionBackendImpl* transaction)
237 {
238     IDB_TRACE("CreateIndexOperation");
239     if (!m_objectStore->backingStore()->createIndex(transaction->backingStoreTransaction(), m_objectStore->databaseId(), m_objectStore->id(), m_index->id(), m_index->name(), m_index->keyPath(), m_index->unique(), m_index->multiEntry())) {
240         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", m_index->name().utf8().data())));
241         return;
242     }
243 }
244
245 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(int64_t indexId)
246 {
247     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(indexId);
248     ASSERT(index);
249     return index.release();
250 }
251
252 void IDBObjectStoreBackendImpl::deleteIndex(int64_t indexId, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
253 {
254     ASSERT(m_indexes.contains(indexId));
255
256     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(indexId);
257     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
258     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
259
260     if (!transaction->scheduleTask(DeleteIndexOperation::create(this, index), DeleteIndexAbortOperation::create(this, index))) {
261         ec = IDBDatabaseException::TransactionInactiveError;
262         return;
263     }
264     m_indexes.remove(indexId);
265 }
266
267 void IDBObjectStoreBackendImpl::DeleteIndexOperation::perform(IDBTransactionBackendImpl* transaction)
268 {
269     IDB_TRACE("DeleteIndexOperation");
270     m_objectStore->backingStore()->deleteIndex(transaction->backingStoreTransaction(), m_objectStore->databaseId(), m_objectStore->id(), m_index->id());
271 }
272
273 void IDBObjectStoreBackendImpl::loadIndexes()
274 {
275     Vector<IDBIndexMetadata> indexes = backingStore()->getIndexes(databaseId(), m_metadata.id);
276
277     for (size_t i = 0; i < indexes.size(); ++i)
278         m_indexes.set(indexes[i].id, IDBIndexBackendImpl::create(m_database, indexes[i]));
279 }
280
281 void IDBObjectStoreBackendImpl::CreateIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
282 {
283     ASSERT(!transaction);
284     ASSERT(m_objectStore->m_indexes.contains(m_index->id()));
285     m_objectStore->m_indexes.remove(m_index->id());
286 }
287
288 void IDBObjectStoreBackendImpl::DeleteIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
289 {
290     ASSERT(!transaction);
291     ASSERT(!m_objectStore->m_indexes.contains(m_index->id()));
292     m_objectStore->m_indexes.set(m_index->id(), m_index);
293 }
294
295 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::generateKey(PassRefPtr<IDBBackingStore> backingStore, PassRefPtr<IDBTransactionBackendImpl> transaction, int64_t databaseId, int64_t objectStoreId)
296 {
297     const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
298     int64_t currentNumber;
299     bool ok = backingStore->getKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId, objectStoreId, currentNumber);
300     if (!ok) {
301         LOG_ERROR("Failed to getKeyGeneratorCurrentNumber");
302         return IDBKey::createInvalid();
303     }
304     if (currentNumber < 0 || currentNumber > maxGeneratorValue)
305         return IDBKey::createInvalid();
306
307     return IDBKey::createNumber(currentNumber);
308 }
309
310 bool IDBObjectStoreBackendImpl::updateKeyGenerator(PassRefPtr<IDBBackingStore> backingStore, PassRefPtr<IDBTransactionBackendImpl> transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey* key, bool checkCurrent)
311 {
312     ASSERT(key && key->type() == IDBKey::NumberType);
313     return backingStore->maybeUpdateKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId, objectStoreId, static_cast<int64_t>(floor(key->number())) + 1, checkCurrent);
314 }
315
316 } // namespace WebCore
317
318 #endif