1/*
2 * Copyright (C) 2015 Apple 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "MemoryIndexCursor.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBCursorInfo.h"
32#include "IDBGetResult.h"
33#include "IndexValueStore.h"
34#include "Logging.h"
35#include "MemoryCursor.h"
36#include "MemoryIndex.h"
37#include "MemoryObjectStore.h"
38
39namespace WebCore {
40namespace IDBServer {
41
42MemoryIndexCursor::MemoryIndexCursor(MemoryIndex& index, const IDBCursorInfo& info)
43 : MemoryCursor(info)
44 , m_index(index)
45{
46 LOG(IndexedDB, "MemoryIndexCursor::MemoryIndexCursor %s", info.range().loggingString().utf8().data());
47
48 auto* valueStore = m_index.valueStore();
49 if (!valueStore)
50 return;
51
52 if (m_info.isDirectionForward())
53 m_currentIterator = valueStore->find(m_info.range().lowerKey, m_info.range().lowerOpen);
54 else
55 m_currentIterator = valueStore->reverseFind(m_info.range().upperKey, m_info.duplicity(), m_info.range().upperOpen);
56
57 if (m_currentIterator.isValid() && m_info.range().containsKey(m_currentIterator.key())) {
58 m_currentKey = m_currentIterator.key();
59 m_currentPrimaryKey = m_currentIterator.primaryKey();
60 m_index.cursorDidBecomeClean(*this);
61 } else
62 m_currentIterator.invalidate();
63}
64
65MemoryIndexCursor::~MemoryIndexCursor() = default;
66
67void MemoryIndexCursor::currentData(IDBGetResult& getResult)
68{
69 if (!m_currentIterator.isValid()) {
70 getResult = { };
71 return;
72 }
73
74 if (m_info.cursorType() == IndexedDB::CursorType::KeyOnly)
75 getResult = { m_currentKey, m_currentPrimaryKey };
76 else {
77 IDBValue value = { m_index.objectStore().valueForKey(m_currentPrimaryKey), { }, { }, { } };
78 getResult = { m_currentKey, m_currentPrimaryKey, WTFMove(value), m_index.objectStore().info().keyPath() };
79 }
80}
81
82void MemoryIndexCursor::iterate(const IDBKeyData& key, const IDBKeyData& primaryKey, uint32_t count, IDBGetResult& getResult)
83{
84 LOG(IndexedDB, "MemoryIndexCursor::iterate to key %s, %u count", key.loggingString().utf8().data(), count);
85
86#ifndef NDEBUG
87 if (primaryKey.isValid())
88 ASSERT(key.isValid());
89#endif
90
91 if (key.isValid()) {
92 // Cannot iterate by both a count and to a key
93 ASSERT(!count);
94
95 auto* valueStore = m_index.valueStore();
96 if (!valueStore) {
97 m_currentKey = { };
98 m_currentPrimaryKey = { };
99 getResult = { };
100 return;
101 }
102
103 if (primaryKey.isValid()) {
104 if (m_info.isDirectionForward())
105 m_currentIterator = valueStore->find(key, primaryKey);
106 else
107 m_currentIterator = valueStore->reverseFind(key, primaryKey, m_info.duplicity());
108 } else {
109 if (m_info.isDirectionForward())
110 m_currentIterator = valueStore->find(key);
111 else
112 m_currentIterator = valueStore->reverseFind(key, m_info.duplicity());
113 }
114
115 if (m_currentIterator.isValid() && !m_info.range().containsKey(m_currentIterator.key()))
116 m_currentIterator.invalidate();
117
118 if (!m_currentIterator.isValid()) {
119 m_currentKey = { };
120 m_currentPrimaryKey = { };
121 getResult = { };
122 return;
123 }
124
125 m_index.cursorDidBecomeClean(*this);
126
127 m_currentKey = m_currentIterator.key();
128 m_currentPrimaryKey = m_currentIterator.primaryKey();
129 currentData(getResult);
130
131 return;
132 }
133
134 // If there was not a valid key argument and no positive count argument
135 // that means the default iteration count of "1"
136 if (!count)
137 count = 1;
138
139 if (!m_currentIterator.isValid()) {
140 auto* valueStore = m_index.valueStore();
141 if (!valueStore) {
142 m_currentKey = { };
143 m_currentPrimaryKey = { };
144 getResult = { };
145 return;
146 }
147
148 switch (m_info.cursorDirection()) {
149 case IndexedDB::CursorDirection::Next:
150 m_currentIterator = valueStore->find(m_currentKey, m_currentPrimaryKey);
151 break;
152 case IndexedDB::CursorDirection::Nextunique:
153 m_currentIterator = valueStore->find(m_currentKey, true);
154 break;
155 case IndexedDB::CursorDirection::Prev:
156 m_currentIterator = valueStore->reverseFind(m_currentKey, m_currentPrimaryKey, m_info.duplicity());
157 break;
158 case IndexedDB::CursorDirection::Prevunique:
159 m_currentIterator = valueStore->reverseFind(m_currentKey, m_info.duplicity(), true);
160 break;
161 }
162
163 if (!m_currentIterator.isValid()) {
164 m_currentKey = { };
165 m_currentPrimaryKey = { };
166 getResult = { };
167 return;
168 }
169
170 m_index.cursorDidBecomeClean(*this);
171
172 // If we restored the current iterator and it does *not* match the current key/primaryKey,
173 // then it is the next record in line and we should consider that an iteration.
174 if (m_currentKey != m_currentIterator.key() || m_currentPrimaryKey != m_currentIterator.primaryKey())
175 --count;
176 }
177
178 ASSERT(m_currentIterator.isValid());
179
180 while (count) {
181 if (m_info.duplicity() == CursorDuplicity::NoDuplicates)
182 m_currentIterator.nextIndexEntry();
183 else
184 ++m_currentIterator;
185
186 if (!m_currentIterator.isValid())
187 break;
188
189 --count;
190 }
191
192 if (m_currentIterator.isValid() && !m_info.range().containsKey(m_currentIterator.key()))
193 m_currentIterator.invalidate();
194
195 // Not having a valid iterator after finishing any iteration means we've reached the end of the cursor.
196 if (!m_currentIterator.isValid()) {
197 m_currentKey = { };
198 m_currentPrimaryKey = { };
199 getResult = { };
200 return;
201 }
202
203 m_currentKey = m_currentIterator.key();
204 m_currentPrimaryKey = m_currentIterator.primaryKey();
205 currentData(getResult);
206}
207
208void MemoryIndexCursor::indexRecordsAllChanged()
209{
210 m_currentIterator.invalidate();
211 m_index.cursorDidBecomeDirty(*this);
212}
213
214void MemoryIndexCursor::indexValueChanged(const IDBKeyData& key, const IDBKeyData& primaryKey)
215{
216 if (m_currentKey != key || m_currentPrimaryKey != primaryKey)
217 return;
218
219 m_currentIterator.invalidate();
220 m_index.cursorDidBecomeDirty(*this);
221}
222
223} // namespace IDBServer
224} // namespace WebCore
225
226#endif // ENABLE(INDEXED_DATABASE)
227