Skip to content

Commit ad24141

Browse files
committed
Merge branch 'develop'
2 parents f161d2d + e691c79 commit ad24141

File tree

6 files changed

+483
-29
lines changed

6 files changed

+483
-29
lines changed

sqlitecipher/sqlcachedresult.cpp

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
/****************************************************************************
2+
**
3+
** Copyright (C) 2016 The Qt Company Ltd.
4+
** Contact: https://www.qt.io/licensing/
5+
**
6+
** This file is part of the QtSql module of the Qt Toolkit.
7+
**
8+
** $QT_BEGIN_LICENSE:LGPL$
9+
** Commercial License Usage
10+
** Licensees holding valid commercial Qt licenses may use this file in
11+
** accordance with the commercial license agreement provided with the
12+
** Software or, alternatively, in accordance with the terms contained in
13+
** a written agreement between you and The Qt Company. For licensing terms
14+
** and conditions see https://www.qt.io/terms-conditions. For further
15+
** information use the contact form at https://www.qt.io/contact-us.
16+
**
17+
** GNU Lesser General Public License Usage
18+
** Alternatively, this file may be used under the terms of the GNU Lesser
19+
** General Public License version 3 as published by the Free Software
20+
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21+
** packaging of this file. Please review the following information to
22+
** ensure the GNU Lesser General Public License version 3 requirements
23+
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24+
**
25+
** GNU General Public License Usage
26+
** Alternatively, this file may be used under the terms of the GNU
27+
** General Public License version 2.0 or (at your option) the GNU General
28+
** Public license version 3 or any later version approved by the KDE Free
29+
** Qt Foundation. The licenses are as published by the Free Software
30+
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31+
** included in the packaging of this file. Please review the following
32+
** information to ensure the GNU General Public License requirements will
33+
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34+
** https://www.gnu.org/licenses/gpl-3.0.html.
35+
**
36+
** $QT_END_LICENSE$
37+
**
38+
****************************************************************************/
39+
40+
#include "sqlcachedresult_p.h"
41+
42+
QT_BEGIN_NAMESPACE
43+
44+
/*
45+
SqlCachedResult is a convenience class for databases that only allow
46+
forward only fetching. It will cache all the results so we can iterate
47+
backwards over the results again.
48+
All you need to do is to inherit from SqlCachedResult and reimplement
49+
gotoNext(). gotoNext() will have a reference to the internal cache and
50+
will give you an index where you can start filling in your data. Special
51+
case: If the user actually wants a forward-only query, idx will be -1
52+
to indicate that we are not interested in the actual values.
53+
*/
54+
55+
static const uint initial_cache_size = 128;
56+
57+
class SqlCachedResultPrivate
58+
{
59+
public:
60+
SqlCachedResultPrivate();
61+
bool canSeek(int i) const;
62+
inline int cacheCount() const;
63+
void init(int count, bool fo);
64+
void cleanup();
65+
int nextIndex();
66+
void revertLast();
67+
68+
SqlCachedResult::ValueCache cache;
69+
int rowCacheEnd;
70+
int colCount;
71+
bool forwardOnly;
72+
bool atEnd;
73+
};
74+
75+
SqlCachedResultPrivate::SqlCachedResultPrivate():
76+
rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false)
77+
{
78+
}
79+
80+
void SqlCachedResultPrivate::cleanup()
81+
{
82+
cache.clear();
83+
forwardOnly = false;
84+
atEnd = false;
85+
colCount = 0;
86+
rowCacheEnd = 0;
87+
}
88+
89+
void SqlCachedResultPrivate::init(int count, bool fo)
90+
{
91+
Q_ASSERT(count);
92+
cleanup();
93+
forwardOnly = fo;
94+
colCount = count;
95+
if (fo) {
96+
cache.resize(count);
97+
rowCacheEnd = count;
98+
} else {
99+
cache.resize(initial_cache_size * count);
100+
}
101+
}
102+
103+
int SqlCachedResultPrivate::nextIndex()
104+
{
105+
if (forwardOnly)
106+
return 0;
107+
int newIdx = rowCacheEnd;
108+
if (newIdx + colCount > cache.size())
109+
cache.resize(qMin(cache.size() * 2, cache.size() + 10000));
110+
rowCacheEnd += colCount;
111+
112+
return newIdx;
113+
}
114+
115+
bool SqlCachedResultPrivate::canSeek(int i) const
116+
{
117+
if (forwardOnly || i < 0)
118+
return false;
119+
return rowCacheEnd >= (i + 1) * colCount;
120+
}
121+
122+
void SqlCachedResultPrivate::revertLast()
123+
{
124+
if (forwardOnly)
125+
return;
126+
rowCacheEnd -= colCount;
127+
}
128+
129+
inline int SqlCachedResultPrivate::cacheCount() const
130+
{
131+
Q_ASSERT(!forwardOnly);
132+
Q_ASSERT(colCount);
133+
return rowCacheEnd / colCount;
134+
}
135+
136+
//////////////
137+
138+
SqlCachedResult::SqlCachedResult(const QSqlDriver * db): QSqlResult (db)
139+
{
140+
d = new SqlCachedResultPrivate();
141+
}
142+
143+
SqlCachedResult::~SqlCachedResult()
144+
{
145+
delete d;
146+
}
147+
148+
void SqlCachedResult::init(int colCount)
149+
{
150+
d->init(colCount, isForwardOnly());
151+
}
152+
153+
bool SqlCachedResult::fetch(int i)
154+
{
155+
if ((!isActive()) || (i < 0))
156+
return false;
157+
if (at() == i)
158+
return true;
159+
if (d->forwardOnly) {
160+
// speed hack - do not copy values if not needed
161+
if (at() > i || at() == QSql::AfterLastRow)
162+
return false;
163+
while(at() < i - 1) {
164+
if (!gotoNext(d->cache, -1))
165+
return false;
166+
setAt(at() + 1);
167+
}
168+
if (!gotoNext(d->cache, 0))
169+
return false;
170+
setAt(at() + 1);
171+
return true;
172+
}
173+
if (d->canSeek(i)) {
174+
setAt(i);
175+
return true;
176+
}
177+
if (d->rowCacheEnd > 0)
178+
setAt(d->cacheCount());
179+
while (at() < i + 1) {
180+
if (!cacheNext()) {
181+
if (d->canSeek(i))
182+
break;
183+
return false;
184+
}
185+
}
186+
setAt(i);
187+
188+
return true;
189+
}
190+
191+
bool SqlCachedResult::fetchNext()
192+
{
193+
if (d->canSeek(at() + 1)) {
194+
setAt(at() + 1);
195+
return true;
196+
}
197+
return cacheNext();
198+
}
199+
200+
bool SqlCachedResult::fetchPrevious()
201+
{
202+
return fetch(at() - 1);
203+
}
204+
205+
bool SqlCachedResult::fetchFirst()
206+
{
207+
if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
208+
return false;
209+
}
210+
if (d->canSeek(0)) {
211+
setAt(0);
212+
return true;
213+
}
214+
return cacheNext();
215+
}
216+
217+
bool SqlCachedResult::fetchLast()
218+
{
219+
if (d->atEnd) {
220+
if (d->forwardOnly)
221+
return false;
222+
else
223+
return fetch(d->cacheCount() - 1);
224+
}
225+
226+
int i = at();
227+
while (fetchNext())
228+
++i; /* brute force */
229+
if (d->forwardOnly && at() == QSql::AfterLastRow) {
230+
setAt(i);
231+
return true;
232+
} else {
233+
return fetch(i);
234+
}
235+
}
236+
237+
QVariant SqlCachedResult::data(int i)
238+
{
239+
int idx = d->forwardOnly ? i : at() * d->colCount + i;
240+
if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
241+
return QVariant();
242+
243+
return d->cache.at(idx);
244+
}
245+
246+
bool SqlCachedResult::isNull(int i)
247+
{
248+
int idx = d->forwardOnly ? i : at() * d->colCount + i;
249+
if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
250+
return true;
251+
252+
return d->cache.at(idx).isNull();
253+
}
254+
255+
void SqlCachedResult::cleanup()
256+
{
257+
setAt(QSql::BeforeFirstRow);
258+
setActive(false);
259+
d->cleanup();
260+
}
261+
262+
void SqlCachedResult::clearValues()
263+
{
264+
setAt(QSql::BeforeFirstRow);
265+
d->rowCacheEnd = 0;
266+
d->atEnd = false;
267+
}
268+
269+
bool SqlCachedResult::cacheNext()
270+
{
271+
if (d->atEnd)
272+
return false;
273+
274+
if(isForwardOnly()) {
275+
d->cache.clear();
276+
d->cache.resize(d->colCount);
277+
}
278+
279+
if (!gotoNext(d->cache, d->nextIndex())) {
280+
d->revertLast();
281+
d->atEnd = true;
282+
return false;
283+
}
284+
setAt(at() + 1);
285+
return true;
286+
}
287+
288+
int SqlCachedResult::colCount() const
289+
{
290+
return d->colCount;
291+
}
292+
293+
SqlCachedResult::ValueCache &SqlCachedResult::cache()
294+
{
295+
return d->cache;
296+
}
297+
298+
void SqlCachedResult::virtual_hook(int id, void *data)
299+
{
300+
QSqlResult::virtual_hook(id, data);
301+
}
302+
303+
void SqlCachedResult::detachFromResultSet()
304+
{
305+
cleanup();
306+
}
307+
308+
void SqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
309+
{
310+
QSqlResult::setNumericalPrecisionPolicy(policy);
311+
cleanup();
312+
}
313+
314+
QT_END_NAMESPACE

0 commit comments

Comments
 (0)