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 "IDBObjectStoreBackendImpl.h"
40
41 namespace WebCore {
42
IDBIndexBackendImpl(IDBBackingStore * backingStore,int64_t databaseId,const IDBObjectStoreBackendImpl * objectStoreBackend,int64_t id,const String & name,const String & storeName,const String & keyPath,bool unique)43 IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreBackendImpl* objectStoreBackend, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique)
44 : m_backingStore(backingStore)
45 , m_databaseId(databaseId)
46 , m_objectStoreBackend(objectStoreBackend)
47 , m_id(id)
48 , m_name(name)
49 , m_storeName(storeName)
50 , m_keyPath(keyPath)
51 , m_unique(unique)
52 {
53 }
54
IDBIndexBackendImpl(IDBBackingStore * backingStore,int64_t databaseId,const IDBObjectStoreBackendImpl * objectStoreBackend,const String & name,const String & storeName,const String & keyPath,bool unique)55 IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreBackendImpl* objectStoreBackend, const String& name, const String& storeName, const String& keyPath, bool unique)
56 : m_backingStore(backingStore)
57 , m_databaseId(databaseId)
58 , m_objectStoreBackend(objectStoreBackend)
59 , m_id(InvalidId)
60 , m_name(name)
61 , m_storeName(storeName)
62 , m_keyPath(keyPath)
63 , m_unique(unique)
64 {
65 }
66
~IDBIndexBackendImpl()67 IDBIndexBackendImpl::~IDBIndexBackendImpl()
68 {
69 }
70
openCursorInternal(ScriptExecutionContext *,PassRefPtr<IDBIndexBackendImpl> index,PassRefPtr<IDBKeyRange> range,unsigned short untypedDirection,IDBCursorBackendInterface::CursorType cursorType,PassRefPtr<IDBCallbacks> callbacks,PassRefPtr<IDBTransactionBackendInterface> transaction)71 void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
72 {
73 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
74
75 RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
76
77 switch (cursorType) {
78 case IDBCursorBackendInterface::IndexKeyCursor:
79 backingStoreCursor = index->m_backingStore->openIndexKeyCursor(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), range.get(), direction);
80 break;
81 case IDBCursorBackendInterface::IndexCursor:
82 backingStoreCursor = index->m_backingStore->openIndexCursor(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), range.get(), direction);
83 break;
84 case IDBCursorBackendInterface::ObjectStoreCursor:
85 case IDBCursorBackendInterface::InvalidCursorType:
86 ASSERT_NOT_REACHED();
87 break;
88 }
89
90 if (!backingStoreCursor) {
91 callbacks->onSuccess(SerializedScriptValue::nullValue());
92 return;
93 }
94
95 ExceptionCode ec = 0;
96 RefPtr<IDBObjectStoreBackendInterface> objectStore = transaction->objectStore(index->m_storeName, ec);
97 ASSERT(objectStore && !ec);
98
99 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), direction, cursorType, transaction.get(), objectStore.get());
100 callbacks->onSuccess(cursor.release());
101 }
102
openCursor(PassRefPtr<IDBKeyRange> prpKeyRange,unsigned short direction,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transactionPtr,ExceptionCode & ec)103 void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
104 {
105 RefPtr<IDBIndexBackendImpl> index = this;
106 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
107 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
108 RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
109 if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexCursor, callbacks, transaction)))
110 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
111 }
112
openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange,unsigned short direction,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transactionPtr,ExceptionCode & ec)113 void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
114 {
115 RefPtr<IDBIndexBackendImpl> index = this;
116 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
117 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
118 RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
119 if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexKeyCursor, callbacks, transaction)))
120 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
121 }
122
getInternal(ScriptExecutionContext *,PassRefPtr<IDBIndexBackendImpl> index,PassRefPtr<IDBKey> key,bool getObject,PassRefPtr<IDBCallbacks> callbacks)123 void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks)
124 {
125 // FIXME: Split getInternal into two functions, getting rid off |getObject|.
126 if (getObject) {
127 String value = index->m_backingStore->getObjectViaIndex(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), *key);
128 if (value.isNull()) {
129 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
130 return;
131 }
132 callbacks->onSuccess(SerializedScriptValue::createFromWire(value));
133 } else {
134 RefPtr<IDBKey> keyResult = index->m_backingStore->getPrimaryKeyViaIndex(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), *key);
135 if (!keyResult) {
136 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
137 return;
138 }
139 callbacks->onSuccess(keyResult.get());
140 }
141 }
142
get(PassRefPtr<IDBKey> prpKey,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)143 void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
144 {
145 RefPtr<IDBIndexBackendImpl> index = this;
146 RefPtr<IDBKey> key = prpKey;
147 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
148 if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, true, callbacks)))
149 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
150 }
151
getKey(PassRefPtr<IDBKey> prpKey,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)152 void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
153 {
154 RefPtr<IDBIndexBackendImpl> index = this;
155 RefPtr<IDBKey> key = prpKey;
156 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
157 if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, false, callbacks)))
158 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
159 }
160
addingKeyAllowed(IDBKey * key)161 bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key)
162 {
163 if (!m_unique)
164 return true;
165
166 return !m_backingStore->keyExistsInIndex(m_databaseId, m_objectStoreBackend->id(), m_id, *key);
167 }
168
169 } // namespace WebCore
170
171 #endif // ENABLE(INDEXED_DATABASE)
172