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

Last change on this file since 135 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 7.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 return false;
189 }
190 setAt(i);
191
192 return true;
193}
194
195bool QSqlCachedResult::fetchNext()
196{
197 if (d->canSeek(at() + 1)) {
198 setAt(at() + 1);
199 return true;
200 }
201 return cacheNext();
202}
203
204bool QSqlCachedResult::fetchPrevious()
205{
206 return fetch(at() - 1);
207}
208
209bool QSqlCachedResult::fetchFirst()
210{
211 if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
212 return false;
213 }
214 if (d->canSeek(0)) {
215 setAt(0);
216 return true;
217 }
218 return cacheNext();
219}
220
221bool QSqlCachedResult::fetchLast()
222{
223 if (d->atEnd) {
224 if (d->forwardOnly)
225 return false;
226 else
227 return fetch(d->cacheCount() - 1);
228 }
229
230 int i = at();
231 while (fetchNext())
232 ++i; /* brute force */
233 if (d->forwardOnly && at() == QSql::AfterLastRow) {
234 setAt(i);
235 return true;
236 } else {
237 return fetch(i);
238 }
239}
240
241QVariant QSqlCachedResult::data(int i)
242{
243 int idx = d->forwardOnly ? i : at() * d->colCount + i;
244 if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
245 return QVariant();
246
247 return d->cache.at(idx);
248}
249
250bool QSqlCachedResult::isNull(int i)
251{
252 int idx = d->forwardOnly ? i : at() * d->colCount + i;
253 if (i > d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
254 return true;
255
256 return d->cache.at(idx).isNull();
257}
258
259void QSqlCachedResult::cleanup()
260{
261 setAt(QSql::BeforeFirstRow);
262 setActive(false);
263 d->cleanup();
264}
265
266void QSqlCachedResult::clearValues()
267{
268 setAt(QSql::BeforeFirstRow);
269 d->rowCacheEnd = 0;
270 d->atEnd = false;
271}
272
273bool QSqlCachedResult::cacheNext()
274{
275 if (d->atEnd)
276 return false;
277
278 if (!gotoNext(d->cache, d->nextIndex())) {
279 d->revertLast();
280 d->atEnd = true;
281 return false;
282 }
283 setAt(at() + 1);
284 return true;
285}
286
287int QSqlCachedResult::colCount() const
288{
289 return d->colCount;
290}
291
292QSqlCachedResult::ValueCache &QSqlCachedResult::cache()
293{
294 return d->cache;
295}
296
297QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.