source: trunk/src/sql/kernel/qsqlresult.cpp@ 160

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

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

File size: 25.4 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 "qvariant.h"
43#include "qhash.h"
44#include "qregexp.h"
45#include "qsqlerror.h"
46#include "qsqlfield.h"
47#include "qsqlrecord.h"
48#include "qsqlresult.h"
49#include "qvector.h"
50#include "qsqldriver.h"
51
52QT_BEGIN_NAMESPACE
53
54struct QHolder {
55 QHolder(const QString& hldr = QString(), int index = -1): holderName(hldr), holderPos(index) {}
56 bool operator==(const QHolder& h) const { return h.holderPos == holderPos && h.holderName == holderName; }
57 bool operator!=(const QHolder& h) const { return h.holderPos != holderPos || h.holderName != holderName; }
58 QString holderName;
59 int holderPos;
60};
61
62class QSqlResultPrivate
63{
64public:
65 QSqlResultPrivate(QSqlResult* d)
66 : q(d), sqldriver(0), idx(QSql::BeforeFirstRow), active(false),
67 isSel(false), forwardOnly(false), bindCount(0), binds(QSqlResult::PositionalBinding)
68 {}
69
70 void clearValues()
71 {
72 values.clear();
73 bindCount = 0;
74 }
75
76 void resetBindCount()
77 {
78 bindCount = 0;
79 }
80
81 void clearIndex()
82 {
83 indexes.clear();
84 holders.clear();
85 types.clear();
86 }
87
88 void clear()
89 {
90 clearValues();
91 clearIndex();;
92 }
93
94 QString positionalToNamedBinding();
95 QString namedToPositionalBinding();
96 QString holderAt(int index) const;
97
98public:
99 QSqlResult* q;
100 const QSqlDriver* sqldriver;
101 int idx;
102 QString sql;
103 bool active;
104 bool isSel;
105 QSqlError error;
106 bool forwardOnly;
107
108 int bindCount;
109 QSqlResult::BindingSyntax binds;
110
111 QString executedQuery;
112 QHash<int, QSql::ParamType> types;
113 QVector<QVariant> values;
114 typedef QHash<QString, int> IndexMap;
115 IndexMap indexes;
116
117 typedef QVector<QHolder> QHolderVector;
118 QHolderVector holders;
119};
120
121QString QSqlResultPrivate::holderAt(int index) const
122{
123 return indexes.key(index);
124}
125
126// return a unique id for bound names
127static QString qFieldSerial(int i)
128{
129 ushort arr[] = { ':', 'f', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
130 ushort *ptr = &arr[1];
131
132 while (i > 0) {
133 *(++ptr) = 'a' + i % 16;
134 i >>= 4;
135 }
136
137 return QString::fromUtf16(arr, int(ptr - arr) + 1);
138}
139
140static bool qIsAlnum(QChar ch)
141{
142 uint u = uint(ch.unicode());
143 // matches [a-zA-Z0-9_]
144 return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_';
145}
146
147QString QSqlResultPrivate::positionalToNamedBinding()
148{
149 int n = sql.size();
150
151 QString result;
152 result.reserve(n * 5 / 4);
153 bool inQuote = false;
154 int count = 0;
155
156 for (int i = 0; i < n; ++i) {
157 QChar ch = sql.at(i);
158 if (ch == QLatin1Char('?') && !inQuote) {
159 result += qFieldSerial(count++);
160 } else {
161 if (ch == QLatin1Char('\''))
162 inQuote = !inQuote;
163 result += ch;
164 }
165 }
166 result.squeeze();
167 return result;
168}
169
170QString QSqlResultPrivate::namedToPositionalBinding()
171{
172 int n = sql.size();
173
174 QString result;
175 result.reserve(n);
176 bool inQuote = false;
177 int count = 0;
178 int i = 0;
179
180 while (i < n) {
181 QChar ch = sql.at(i);
182 if (ch == QLatin1Char(':') && !inQuote
183 && (i == 0 || sql.at(i - 1) != QLatin1Char(':'))
184 && (i < n - 1 && qIsAlnum(sql.at(i + 1)))) {
185 int pos = i + 2;
186 while (pos < n && qIsAlnum(sql.at(pos)))
187 ++pos;
188 indexes[sql.mid(i, pos - i)] = count++;
189 result += QLatin1Char('?');
190 i = pos;
191 } else {
192 if (ch == QLatin1Char('\''))
193 inQuote = !inQuote;
194 result += ch;
195 ++i;
196 }
197 }
198 result.squeeze();
199 return result;
200}
201
202/*!
203 \class QSqlResult
204 \brief The QSqlResult class provides an abstract interface for
205 accessing data from specific SQL databases.
206
207 \ingroup database
208 \inmodule QtSql
209
210 Normally, you would use QSqlQuery instead of QSqlResult, since
211 QSqlQuery provides a generic wrapper for database-specific
212 implementations of QSqlResult.
213
214 If you are implementing your own SQL driver (by subclassing
215 QSqlDriver), you will need to provide your own QSqlResult
216 subclass that implements all the pure virtual functions and other
217 virtual functions that you need.
218
219 \sa QSqlDriver
220*/
221
222/*!
223 \enum QSqlResult::BindingSyntax
224
225 This enum type specifies the different syntaxes for specifying
226 placeholders in prepared queries.
227
228 \value PositionalBinding Use the ODBC-style positional syntax, with "?" as placeholders.
229 \value NamedBinding Use the Oracle-style syntax with named placeholders (e.g., ":id")
230 \omitvalue BindByPosition
231 \omitvalue BindByName
232
233 \sa bindingSyntax()
234*/
235
236/*!
237 \enum QSqlResult::VirtualHookOperation
238 \internal
239*/
240
241/*!
242 Creates a QSqlResult using database driver \a db. The object is
243 initialized to an inactive state.
244
245 \sa isActive(), driver()
246*/
247
248QSqlResult::QSqlResult(const QSqlDriver *db)
249{
250 d = new QSqlResultPrivate(this);
251 d->sqldriver = db;
252}
253
254/*!
255 Destroys the object and frees any allocated resources.
256*/
257
258QSqlResult::~QSqlResult()
259{
260 delete d;
261}
262
263/*!
264 Sets the current query for the result to \a query. You must call
265 reset() to execute the query on the database.
266
267 \sa reset(), lastQuery()
268*/
269
270void QSqlResult::setQuery(const QString& query)
271{
272 d->sql = query;
273}
274
275/*!
276 Returns the current SQL query text, or an empty string if there
277 isn't one.
278
279 \sa setQuery()
280*/
281
282QString QSqlResult::lastQuery() const
283{
284 return d->sql;
285}
286
287/*!
288 Returns the current (zero-based) row position of the result. May
289 return the special values QSql::BeforeFirstRow or
290 QSql::AfterLastRow.
291
292 \sa setAt(), isValid()
293*/
294int QSqlResult::at() const
295{
296 return d->idx;
297}
298
299
300/*!
301 Returns true if the result is positioned on a valid record (that
302 is, the result is not positioned before the first or after the
303 last record); otherwise returns false.
304
305 \sa at()
306*/
307
308bool QSqlResult::isValid() const
309{
310 return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
311}
312
313/*!
314 \fn bool QSqlResult::isNull(int index)
315
316 Returns true if the field at position \a index in the current row
317 is null; otherwise returns false.
318*/
319
320/*!
321 Returns true if the result has records to be retrieved; otherwise
322 returns false.
323*/
324
325bool QSqlResult::isActive() const
326{
327 return d->active;
328}
329
330/*!
331 This function is provided for derived classes to set the
332 internal (zero-based) row position to \a index.
333
334 \sa at()
335*/
336
337void QSqlResult::setAt(int index)
338{
339 d->idx = index;
340}
341
342
343/*!
344 This function is provided for derived classes to indicate whether
345 or not the current statement is a SQL \c SELECT statement. The \a
346 select parameter should be true if the statement is a \c SELECT
347 statement; otherwise it should be false.
348
349 \sa isSelect()
350*/
351
352void QSqlResult::setSelect(bool select)
353{
354 d->isSel = select;
355}
356
357/*!
358 Returns true if the current result is from a \c SELECT statement;
359 otherwise returns false.
360
361 \sa setSelect()
362*/
363
364bool QSqlResult::isSelect() const
365{
366 return d->isSel;
367}
368
369/*!
370 Returns the driver associated with the result. This is the object
371 that was passed to the constructor.
372*/
373
374const QSqlDriver *QSqlResult::driver() const
375{
376 return d->sqldriver;
377}
378
379
380/*!
381 This function is provided for derived classes to set the internal
382 active state to \a active.
383
384 \sa isActive()
385*/
386
387void QSqlResult::setActive(bool active)
388{
389 if (active && d->executedQuery.isEmpty())
390 d->executedQuery = d->sql;
391
392 d->active = active;
393}
394
395/*!
396 This function is provided for derived classes to set the last
397 error to \a error.
398
399 \sa lastError()
400*/
401
402void QSqlResult::setLastError(const QSqlError &error)
403{
404 d->error = error;
405}
406
407
408/*!
409 Returns the last error associated with the result.
410*/
411
412QSqlError QSqlResult::lastError() const
413{
414 return d->error;
415}
416
417/*!
418 \fn int QSqlResult::size()
419
420 Returns the size of the \c SELECT result, or -1 if it cannot be
421 determined or if the query is not a \c SELECT statement.
422
423 \sa numRowsAffected()
424*/
425
426/*!
427 \fn int QSqlResult::numRowsAffected()
428
429 Returns the number of rows affected by the last query executed, or
430 -1 if it cannot be determined or if the query is a \c SELECT
431 statement.
432
433 \sa size()
434*/
435
436/*!
437 \fn QVariant QSqlResult::data(int index)
438
439 Returns the data for field \a index in the current row as
440 a QVariant. This function is only called if the result is in
441 an active state and is positioned on a valid record and \a index is
442 non-negative. Derived classes must reimplement this function and
443 return the value of field \a index, or QVariant() if it cannot be
444 determined.
445*/
446
447/*!
448 \fn bool QSqlResult::reset(const QString &query)
449
450 Sets the result to use the SQL statement \a query for subsequent
451 data retrieval.
452
453 Derived classes must reimplement this function and apply the \a
454 query to the database. This function is only called after the
455 result is set to an inactive state and is positioned before the
456 first record of the new result. Derived classes should return
457 true if the query was successful and ready to be used, or false
458 otherwise.
459
460 \sa setQuery()
461*/
462
463/*!
464 \fn bool QSqlResult::fetch(int index)
465
466 Positions the result to an arbitrary (zero-based) row \a index.
467
468 This function is only called if the result is in an active state.
469 Derived classes must reimplement this function and position the
470 result to the row \a index, and call setAt() with an appropriate
471 value. Return true to indicate success, or false to signify
472 failure.
473
474 \sa isActive(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious()
475*/
476
477/*!
478 \fn bool QSqlResult::fetchFirst()
479
480 Positions the result to the first record (row 0) in the result.
481
482 This function is only called if the result is in an active state.
483 Derived classes must reimplement this function and position the
484 result to the first record, and call setAt() with an appropriate
485 value. Return true to indicate success, or false to signify
486 failure.
487
488 \sa fetch(), fetchLast()
489*/
490
491/*!
492 \fn bool QSqlResult::fetchLast()
493
494 Positions the result to the last record (last row) in the result.
495
496 This function is only called if the result is in an active state.
497 Derived classes must reimplement this function and position the
498 result to the last record, and call setAt() with an appropriate
499 value. Return true to indicate success, or false to signify
500 failure.
501
502 \sa fetch(), fetchFirst()
503*/
504
505/*!
506 Positions the result to the next available record (row) in the
507 result.
508
509 This function is only called if the result is in an active
510 state. The default implementation calls fetch() with the next
511 index. Derived classes can reimplement this function and position
512 the result to the next record in some other way, and call setAt()
513 with an appropriate value. Return true to indicate success, or
514 false to signify failure.
515
516 \sa fetch(), fetchPrevious()
517*/
518
519bool QSqlResult::fetchNext()
520{
521 return fetch(at() + 1);
522}
523
524/*!
525 Positions the result to the previous record (row) in the result.
526
527 This function is only called if the result is in an active state.
528 The default implementation calls fetch() with the previous index.
529 Derived classes can reimplement this function and position the
530 result to the next record in some other way, and call setAt()
531 with an appropriate value. Return true to indicate success, or
532 false to signify failure.
533*/
534
535bool QSqlResult::fetchPrevious()
536{
537 return fetch(at() - 1);
538}
539
540/*!
541 Returns true if you can only scroll forward through the result
542 set; otherwise returns false.
543
544 \sa setForwardOnly()
545*/
546bool QSqlResult::isForwardOnly() const
547{
548 return d->forwardOnly;
549}
550
551/*!
552 Sets forward only mode to \a forward. If \a forward is true, only
553 fetchNext() is allowed for navigating the results. Forward only
554 mode needs much less memory since results do not have to be
555 cached. By default, this feature is disabled.
556
557 \sa isForwardOnly(), fetchNext()
558*/
559void QSqlResult::setForwardOnly(bool forward)
560{
561 d->forwardOnly = forward;
562}
563
564/*!
565 Prepares the given \a query, using the underlying database
566 functionality where possible. Returns true if the query is
567 prepared successfully; otherwise returns false.
568
569 \sa prepare()
570*/
571bool QSqlResult::savePrepare(const QString& query)
572{
573 if (!driver())
574 return false;
575 d->clear();
576 d->sql = query;
577 if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
578 return prepare(query);
579
580 if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) {
581 // parse the query to memorize parameter location
582 d->namedToPositionalBinding();