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