1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtSql module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "private/qsqlcachedresult_p.h"
45 #include <qdatetime.h>
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
67 QSqlCachedResultPrivate();
68 bool canSeek(int i
) const;
69 inline int cacheCount() const;
70 void init(int count
, bool fo
);
75 QSqlCachedResult::ValueCache cache
;
82 QSqlCachedResultPrivate::QSqlCachedResultPrivate():
83 rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false)
87 void QSqlCachedResultPrivate::cleanup()
96 void QSqlCachedResultPrivate::init(int count
, bool fo
)
106 cache
.resize(initial_cache_size
* count
);
110 int QSqlCachedResultPrivate::nextIndex()
114 int newIdx
= rowCacheEnd
;
115 if (newIdx
+ colCount
> cache
.size())
116 cache
.resize(qMin(cache
.size() * 2, cache
.size() + 10000));
117 rowCacheEnd
+= colCount
;
122 bool QSqlCachedResultPrivate::canSeek(int i
) const
124 if (forwardOnly
|| i
< 0)
126 return rowCacheEnd
>= (i
+ 1) * colCount
;
129 void QSqlCachedResultPrivate::revertLast()
133 rowCacheEnd
-= colCount
;
136 inline int QSqlCachedResultPrivate::cacheCount() const
138 Q_ASSERT(!forwardOnly
);
140 return rowCacheEnd
/ colCount
;
145 QSqlCachedResult::QSqlCachedResult(const QSqlDriver
* db
): QSqlResult (db
)
147 d
= new QSqlCachedResultPrivate();
150 QSqlCachedResult::~QSqlCachedResult()
155 void QSqlCachedResult::init(int colCount
)
157 d
->init(colCount
, isForwardOnly());
160 bool QSqlCachedResult::fetch(int i
)
162 if ((!isActive()) || (i
< 0))
166 if (d
->forwardOnly
) {
167 // speed hack - do not copy values if not needed
168 if (at() > i
|| at() == QSql::AfterLastRow
)
170 while(at() < i
- 1) {
171 if (!gotoNext(d
->cache
, -1))
175 if (!gotoNext(d
->cache
, 0))
184 if (d
->rowCacheEnd
> 0)
185 setAt(d
->cacheCount());
186 while (at() < i
+ 1) {
198 bool QSqlCachedResult::fetchNext()
200 if (d
->canSeek(at() + 1)) {
207 bool QSqlCachedResult::fetchPrevious()
209 return fetch(at() - 1);
212 bool QSqlCachedResult::fetchFirst()
214 if (d
->forwardOnly
&& at() != QSql::BeforeFirstRow
) {
224 bool QSqlCachedResult::fetchLast()
230 return fetch(d
->cacheCount() - 1);
235 ++i
; /* brute force */
236 if (d
->forwardOnly
&& at() == QSql::AfterLastRow
) {
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
)
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
)
259 return d
->cache
.at(idx
).isNull();
262 void QSqlCachedResult::cleanup()
264 setAt(QSql::BeforeFirstRow
);
269 void QSqlCachedResult::clearValues()
271 setAt(QSql::BeforeFirstRow
);
276 bool QSqlCachedResult::cacheNext()
281 if (!gotoNext(d
->cache
, d
->nextIndex())) {
290 int QSqlCachedResult::colCount() const
295 QSqlCachedResult::ValueCache
&QSqlCachedResult::cache()
300 void QSqlCachedResult::virtual_hook(int id
, void *data
)
303 case QSqlResult::DetachFromResultSet
:
304 case QSqlResult::SetNumericalPrecision
:
308 QSqlResult::virtual_hook(id
, data
);