source: trunk/src/sql/kernel/qsqlcachedresult.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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