IndexedDB: Explicitly send null/undefined/integers to frontend IDBCallbacks
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBIndexBackendImpl.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 "IDBIndexBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "CrossThreadTask.h"
32 #include "IDBBackingStore.h"
33 #include "IDBCallbacks.h"
34 #include "IDBCursorBackendImpl.h"
35 #include "IDBDatabaseBackendImpl.h"
36 #include "IDBDatabaseException.h"
37 #include "IDBKey.h"
38 #include "IDBKeyRange.h"
39 #include "IDBMetadata.h"
40 #include "IDBObjectStoreBackendImpl.h"
41 #include "IDBTracing.h"
42 #include "IDBTransactionBackendImpl.h"
43
44 namespace WebCore {
45
46 IDBIndexBackendImpl::IDBIndexBackendImpl(const IDBDatabaseBackendImpl* database, IDBObjectStoreBackendImpl* objectStoreBackend, int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
47     : m_database(database)
48     , m_objectStoreBackend(objectStoreBackend)
49     , m_id(id)
50     , m_name(name)
51     , m_keyPath(keyPath)
52     , m_unique(unique)
53     , m_multiEntry(multiEntry)
54 {
55 }
56
57 IDBIndexBackendImpl::~IDBIndexBackendImpl()
58 {
59 }
60
61 IDBIndexMetadata IDBIndexBackendImpl::metadata() const
62 {
63     return IDBIndexMetadata(m_name, m_id, m_keyPath, m_unique, m_multiEntry);
64 }
65
66 void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
67 {
68     IDB_TRACE("IDBIndexBackendImpl::openCursorInternal");
69     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
70
71     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
72
73     switch (cursorType) {
74     case IDBCursorBackendInterface::IndexKeyCursor:
75         backingStoreCursor = index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), range.get(), direction);
76         break;
77     case IDBCursorBackendInterface::IndexCursor:
78         backingStoreCursor = index->backingStore()->openIndexCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), range.get(), direction);
79         break;
80     case IDBCursorBackendInterface::ObjectStoreCursor:
81     case IDBCursorBackendInterface::InvalidCursorType:
82         ASSERT_NOT_REACHED();
83         break;
84     }
85
86     if (!backingStoreCursor) {
87         callbacks->onSuccess(static_cast<SerializedScriptValue*>(0));
88         return;
89     }
90
91     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), cursorType, transaction.get(), index->m_objectStoreBackend);
92     callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
93 }
94
95 void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
96 {
97     IDB_TRACE("IDBIndexBackendImpl::openCursor");
98     RefPtr<IDBIndexBackendImpl> index = this;
99     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
100     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
101     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
102     if (!transaction->scheduleTask(
103             createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexCursor, callbacks, transaction)))
104         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
105 }
106
107 void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
108 {
109     IDB_TRACE("IDBIndexBackendImpl::openKeyCursor");
110     RefPtr<IDBIndexBackendImpl> index = this;
111     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
112     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
113     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
114     if (!transaction->scheduleTask(
115             createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexKeyCursor, callbacks, transaction)))
116         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
117 }
118
119 void IDBIndexBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
120 {
121     IDB_TRACE("IDBIndexBackendImpl::countInternal");
122     uint32_t count = 0;
123
124     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), range.get(), IDBCursor::NEXT);
125     if (!backingStoreCursor) {
126         callbacks->onSuccess(count);
127         return;
128     }
129
130     do {
131         ++count;
132     } while (backingStoreCursor->continueFunction(0));
133     backingStoreCursor->close();
134     callbacks->onSuccess(count);
135 }
136
137 void IDBIndexBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
138 {
139     IDB_TRACE("IDBIndexBackendImpl::count");
140     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
141     if (!transaction->scheduleTask(
142             createCallbackTask(&countInternal, this, range, callbacks, transaction)))
143         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
144 }
145
146 void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
147 {
148     IDB_TRACE("IDBIndexBackendImpl::getInternal");
149
150     RefPtr<IDBKey> key;
151
152     if (keyRange->isOnlyKey())
153         key = keyRange->lower();
154     else {
155         RefPtr<IDBBackingStore::Cursor> backingStoreCursor = index->backingStore()->openIndexCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), keyRange.get(), IDBCursor::NEXT);
156
157         if (!backingStoreCursor) {
158             callbacks->onSuccess();
159             return;
160         }
161         key = backingStoreCursor->key();
162         backingStoreCursor->close();
163     }
164
165     RefPtr<IDBKey> primaryKey = index->backingStore()->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), *key);
166
167     String value = index->backingStore()->getObjectStoreRecord(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), *primaryKey);
168
169     if (value.isNull()) {
170         callbacks->onSuccess();
171         return;
172     }
173     if (index->m_objectStoreBackend->autoIncrement() && !index->m_objectStoreBackend->keyPath().isNull()) {
174         callbacks->onSuccess(SerializedScriptValue::createFromWire(value),
175                              primaryKey, index->m_objectStoreBackend->keyPath());
176         return;
177     }
178     callbacks->onSuccess(SerializedScriptValue::createFromWire(value));
179 }
180
181 void IDBIndexBackendImpl::getKeyInternal(ScriptExecutionContext* context, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
182 {
183     IDB_TRACE("IDBIndexBackendImpl::getInternal");
184
185     RefPtr<IDBBackingStore::Cursor> backingStoreCursor =
186             index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), keyRange.get(), IDBCursor::NEXT);
187
188     if (!backingStoreCursor) {
189         callbacks->onSuccess(static_cast<IDBKey*>(0));
190         return;
191     }
192
193     RefPtr<IDBKey> keyResult = index->backingStore()->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), *backingStoreCursor->key());
194     if (!keyResult) {
195         callbacks->onSuccess(static_cast<IDBKey*>(0));
196         backingStoreCursor->close();
197         return;
198     }
199     callbacks->onSuccess(keyResult.get());
200     backingStoreCursor->close();
201 }
202
203
204 void IDBIndexBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
205 {
206     IDB_TRACE("IDBIndexBackendImpl::get");
207     RefPtr<IDBIndexBackendImpl> index = this;
208     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
209     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
210     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
211     if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, keyRange, callbacks, transaction)))
212         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
213 }
214
215 void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
216 {
217     IDB_TRACE("IDBIndexBackendImpl::getKey");
218     RefPtr<IDBIndexBackendImpl> index = this;
219     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
220     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
221     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
222     if (!transaction->scheduleTask(
223             createCallbackTask(&getKeyInternal, index, keyRange, callbacks, transaction)))
224         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
225 }
226
227 } // namespace WebCore
228
229 #endif // ENABLE(INDEXED_DATABASE)