Fixes a crash in QDoubleSpinBox
[qt-netbsd.git] / src / sql / kernel / qsqlcachedresult.cpp
blob16308984f2b306a950b03e0097f84644540c8b50
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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.
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.
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.
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.
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "private/qsqlcachedresult_p.h"
44 #include <qvariant.h>
45 #include <qdatetime.h>
46 #include <qvector.h>
48 QT_BEGIN_NAMESPACE
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.
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.
62 static const uint initial_cache_size = 128;
64 class QSqlCachedResultPrivate
66 public:
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();
75 QSqlCachedResult::ValueCache cache;
76 int rowCacheEnd;
77 int colCount;
78 bool forwardOnly;
79 bool atEnd;
82 QSqlCachedResultPrivate::QSqlCachedResultPrivate():
83 rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false)
87 void QSqlCachedResultPrivate::cleanup()
89 cache.clear();
90 forwardOnly = false;
91 atEnd = false;
92 colCount = 0;
93 rowCacheEnd = 0;
96 void QSqlCachedResultPrivate::init(int count, bool fo)
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);
110 int QSqlCachedResultPrivate::nextIndex()
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;
119 return newIdx;
122 bool QSqlCachedResultPrivate::canSeek(int i) const
124 if (forwardOnly || i < 0)
125 return false;
126 return rowCacheEnd >= (i + 1) * colCount;
129 void QSqlCachedResultPrivate::revertLast()
131 if (forwardOnly)
132 return;
133 rowCacheEnd -= colCount;
136 inline int QSqlCachedResultPrivate::cacheCount() const
138 Q_ASSERT(!forwardOnly);
139 Q_ASSERT(colCount);
140 return rowCacheEnd / colCount;
143 //////////////
145 QSqlCachedResult::QSqlCachedResult(const QSqlDriver * db): QSqlResult (db)
147 d = new QSqlCachedResultPrivate();
150 QSqlCachedResult::~QSqlCachedResult()
152 delete d;
155 void QSqlCachedResult::init(int colCount)
157 d->init(colCount, isForwardOnly());
160 bool QSqlCachedResult::fetch(int i)
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);
175 if (!gotoNext(d->cache, 0))
176 return false;
177 setAt(at() + 1);
178 return true;
180 if (d->canSeek(i)) {
181 setAt(i);
182 return true;
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;
193 setAt(i);
195 return true;
198 bool QSqlCachedResult::fetchNext()
200 if (d->canSeek(at() + 1)) {
201 setAt(at() + 1);
202 return true;
204 return cacheNext();
207 bool QSqlCachedResult::fetchPrevious()
209 return fetch(at() - 1);
212 bool QSqlCachedResult::fetchFirst()
214 if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
215 return false;
217 if (d->canSeek(0)) {
218 setAt(0);
219 return true;
221 return cacheNext();
224 bool QSqlCachedResult::fetchLast()
226 if (d->atEnd) {
227 if (d->forwardOnly)
228 return false;
229 else
230 return fetch(d->cacheCount() - 1);
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);
244 QVariant QSqlCachedResult::data(int i)
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();
250 return d->cache.at(idx);
253 bool QSqlCachedResult::isNull(int i)
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;
259 return d->cache.at(idx).isNull();
262 void QSqlCachedResult::cleanup()
264 setAt(QSql::BeforeFirstRow);
265 setActive(false);
266 d->cleanup();
269 void QSqlCachedResult::clearValues()
271 setAt(QSql::BeforeFirstRow);
272 d->rowCacheEnd = 0;
273 d->atEnd = false;
276 bool QSqlCachedResult::cacheNext()
278 if (d->atEnd)
279 return false;
281 if (!gotoNext(d->cache, d->nextIndex())) {
282 d->revertLast();
283 d->atEnd = true;
284 return false;
286 setAt(at() + 1);
287 return true;
290 int QSqlCachedResult::colCount() const
292 return d->colCount;
295 QSqlCachedResult::ValueCache &QSqlCachedResult::cache()
297 return d->cache;
300 QT_END_NAMESPACE