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

Last change on this file since 1016 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: 26.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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.
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 qt-info@nokia.com.
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#include <QDebug>
52
53QT_BEGIN_NAMESPACE
54
55struct QHolder {
56 QHolder(const QString& hldr = QString(), int index = -1): holderName(hldr), holderPos(index) {}
57 bool operator==(const QHolder& h) const { return h.holderPos == holderPos && h.holderName == holderName; }
58 bool operator!=(const QHolder& h) const { return h.holderPos != holderPos || h.holderName != holderName; }
59 QString holderName;
60 int holderPos;
61};
62
63class QSqlResultPrivate
64{
65public:
66 QSqlResultPrivate(QSqlResult* d)
67 : q(d), sqldriver(0), idx(QSql::BeforeFirstRow), active(false),
68 isSel(false), forwardOnly(false), precisionPolicy(QSql::LowPrecisionDouble), bindCount(0), binds(QSqlResult::PositionalBinding)
69 {}
70
71 void clearValues()
72 {
73 values.clear();
74 bindCount = 0;
75 }
76
77 void resetBindCount()
78 {
79 bindCount = 0;
80 }
81
82 void clearIndex()
83 {
84 indexes.clear();
85 holders.clear();
86 types.clear();
87 }
88
89 void clear()
90 {
91 clearValues();
92 clearIndex();;
93 }
94
95 QString positionalToNamedBinding();
96 QString namedToPositionalBinding();
97 QString holderAt(int index) const;
98
99public:
100 QSqlResult* q;
101 const QSqlDriver* sqldriver;
102 int idx;
103 QString sql;
104 bool active;
105 bool isSel;
106 QSqlError error;
107 bool forwardOnly;
108 QSql::NumericalPrecisionPolicy precisionPolicy;
109
110 int bindCount;
111 QSqlResult::BindingSyntax binds;
112
113 QString executedQuery;
114 QHash<int, QSql::ParamType> types;
115 QVector<QVariant> values;
116 typedef QHash<QString, int> IndexMap;
117 IndexMap indexes;
118
119 typedef QVector<QHolder> QHolderVector;
120 QHolderVector holders;
121};
122
123QString QSqlResultPrivate::holderAt(int index) const
124{
125 return indexes.key(index);
126}
127
128// return a unique id for bound names
129static QString qFieldSerial(int i)
130{
131 ushort arr[] = { ':', 'f', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
132 ushort *ptr = &arr[1];
133
134 while (i > 0) {
135 *(++ptr) = 'a' + i % 16;
136 i >>= 4;
137 }
138
139 return QString(reinterpret_cast<const QChar *>(arr), int(ptr - arr) + 1);
140}
141
142static bool qIsAlnum(QChar ch)
143{
144 uint u = uint(ch.unicode());
145 // matches [a-zA-Z0-9_]
146 return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_';
147}
148
149QString QSqlResultPrivate::positionalToNamedBinding()
150{
151 int n = sql.size();
152
153 QString result;
154 result.reserve(n * 5 / 4);
155 bool inQuote = false;
156 int count = 0;
157
158 for (int i = 0; i < n; ++i) {
159 QChar ch = sql.at(i);
160 if (ch == QLatin1Char('?') && !inQuote) {
161 result += qFieldSerial(count++);
162 } else {
163 if (ch == QLatin1Char('\''))
164 inQuote = !inQuote;
165 result += ch;
166 }
167 }
168 result.squeeze();
169 return result;
170}
171
172QString QSqlResultPrivate::namedToPositionalBinding()
173{
174 int n = sql.size();
175
176 QString result;
177 result.reserve(n);
178 bool inQuote = false;
179 int count = 0;
180 int i = 0;
181
182 while (i < n) {
183 QChar ch = sql.at(i);
184 if (ch == QLatin1Char(':') && !inQuote
185 && (i == 0 || sql.at(i - 1) != QLatin1Char(':'))
186 && (i < n - 1 && qIsAlnum(sql.at(i + 1)))) {
187 int pos = i + 2;
188 while (pos < n && qIsAlnum(sql.at(pos)))
189 ++pos;
190 indexes[sql.mid(i, pos - i)] = count++;
191 result += QLatin1Char('?');
192 i = pos;
193 } else {
194 if (ch == QLatin1Char('\''))
195 inQuote = !inQuote;
196 result += ch;
197 ++i;
198 }
199 }
200 result.squeeze();
201 return result;
202}
203
204/*!
205 \class QSqlResult
206 \brief The QSqlResult class provides an abstract interface for
207 accessing data from specific SQL databases.
208
209 \ingroup database
210 \inmodule QtSql
211
212 Normally, you would use QSqlQuery instead of QSqlResult, since
213 QSqlQuery provides a generic wrapper for database-specific
214 implementations of QSqlResult.
215
216 If you are implementing your own SQL driver (by subclassing
217 QSqlDriver), you will need to provide your own QSqlResult
218 subclass that implements all the pure virtual functions and other
219 virtual functions that you need.
220
221 \sa QSqlDriver
222*/
223
224/*!
225 \enum QSqlResult::BindingSyntax
226
227 This enum type specifies the different syntaxes for specifying
228 placeholders in prepared queries.
229
230 \value PositionalBinding Use the ODBC-style positional syntax, with "?" as placeholders.
231 \value NamedBinding Use the Oracle-style syntax with named placeholders (e.g., ":id")
232 \omitvalue BindByPosition
233 \omitvalue BindByName
234
235 \sa bindingSyntax()
236*/
237
238/*!
239 \enum QSqlResult::VirtualHookOperation
240 \internal
241*/
242
243/*!
244 Creates a QSqlResult using database driver \a db. The object is
245 initialized to an inactive state.
246
247 \sa isActive(), driver()
248*/
249
250QSqlResult::QSqlResult(const QSqlDriver *db)
251{
252 d = new QSqlResultPrivate(this);
253 d->sqldriver = db;
254 if(db) {
255 setNumericalPrecisionPolicy(db->numericalPrecisionPolicy());
256 }
257}
258
259/*!
260 Destroys the object and frees any allocated resources.
261*/
262
263QSqlResult::~QSqlResult()
264{
265 delete d;
266}
267
268/*!
269 Sets the current query for the result to \a query. You must call
270 reset() to execute the query on the database.
271
272 \sa reset(), lastQuery()
273*/
274
275void QSqlResult::setQuery(const QString& query)
276{
277 d->sql = query;
278}
279
280/*!
281 Returns the current SQL query text, or an empty string if there
282 isn't one.
283
284 \sa setQuery()
285*/
286
287QString QSqlResult::lastQuery() const
288{
289 return d->sql;
290}
291
292/*!
293 Returns the current (zero-based) row position of the result. May
294 return the special values QSql::BeforeFirstRow or
295 QSql::AfterLastRow.
296
297 \sa setAt(), isValid()
298*/
299int QSqlResult::at() const
300{
301 return d->idx;
302}
303
304
305/*!
306 Returns true if the result is positioned on a valid record (that
307 is, the result is not positioned before the first or after the
308 last record); otherwise returns false.
309
310 \sa at()
311*/
312
313bool QSqlResult::isValid() const
314{
315 return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
316}
317
318/*!
319 \fn bool QSqlResult::isNull(int index)
320
321 Returns true if the field at position \a index in the current row
322 is null; otherwise returns false.
323*/
324
325/*!
326 Returns true if the result has records to be retrieved; otherwise
327 returns false.
328*/
329
330bool QSqlResult::isActive() const
331{
332 return d->active;
333}
334
335/*!
336 This function is provided for derived classes to set the
337 internal (zero-based) row position to \a index.
338
339 \sa at()
340*/
341
342void QSqlResult::setAt(int index)
343{
344 d->idx = index;
345}
346
347
348/*!
349 This function is provided for derived classes to indicate whether
350 or not the current statement is a SQL \c SELECT statement. The \a
351 select parameter should be true if the statement is a \c SELECT
352 statement; otherwise it should be false.
353
354 \sa isSelect()
355*/
356
357void QSqlResult::setSelect(bool select)
358{
359 d->isSel = select;
360}
361
362/*!
363 Returns true if the current result is from a \c SELECT statement;
364 otherwise returns false.
365
366 \sa setSelect()
367*/
368
369bool QSqlResult::isSelect() const
370{
371 return d->isSel;
372}
373
374/*!
375 Returns the driver associated with the result. This is the object
376 that was passed to the constructor.
377*/
378
379const QSqlDriver *QSqlResult::driver() const
380{
381 return d->sqldriver;
382}
383
384
385/*!
386 This function is provided for derived classes to set the internal
387 active state to \a active.
388
389 \sa isActive()
390*/
391
392void QSqlResult::setActive(bool active)
393{
394 if (active && d->executedQuery.isEmpty())
395 d->executedQuery = d->sql;
396
397 d->active = active;
398}
399
400/*!
401 This function is provided for derived classes to set the last
402 error to \a error.
403
404 \sa lastError()
405*/
406
407void QSqlResult::setLastError(const QSqlError &error)
408{
409 d->error = error;
410}
411
412
413/*!
414 Returns the last error associated with the result.
415*/
416
417QSqlError QSqlResult::lastError() const
418{
419 return d->error;
420}
421
422/*!
423 \fn int QSqlResult::size()
424
425 Returns the size of the \c SELECT result, or -1 if it cannot be
426 determined or if the query is not a \c SELECT statement.
427
428 \sa numRowsAffected()
429*/
430
431/*!
432 \fn int QSqlResult::numRowsAffected()
433
434 Returns the number of rows affected by the last query executed, or
435 -1 if it cannot be determined or if the query is a \c SELECT
436 statement.
437
438 \sa size()
439*/
440
441/*!
442 \fn QVariant QSqlResult::data(int index)
443
444 Returns the data for field \a index in the current row as
445 a QVariant. This function is only called if the result is in
446 an active state and is positioned on a valid record and \a index is
447 non-negative. Derived classes must reimplement this function and
448 return the value of field \a index, or QVariant() if it cannot be
449 determined.
450*/
451
452/*!
453 \fn bool QSqlResult::reset(const QString &query)
454
455 Sets the result to use the SQL statement \a query for subsequent
456 data retrieval.
457
458 Derived classes must reimplement this function and apply the \a
459 query to the database. This function is only called after the
460 result is set to an inactive state and is positioned before the
461 first record of the new result. Derived classes should return
462 true if the query was successful and ready to be used, or false
463 otherwise.
464
465 \sa setQuery()
466*/
467
468/*!
469 \fn bool QSqlResult::fetch(int index)
470
471 Positions the result to an arbitrary (zero-based) row \a index.
472
473 This function is only called if the result is in an active state.
474 Derived classes must reimplement this function and position the
475 result to the row \a index, and call setAt() with an appropriate
476 value. Return true to indicate success, or false to signify
477 failure.
478
479 \sa isActive(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious()
480*/
481
482/*!
483 \fn bool QSqlResult::fetchFirst()
484
485 Positions the result to the first record (row 0) in the result.
486
487 This function is only called if the result is in an active state.
488 Derived classes must reimplement this function and position the
489 result to the first record, and call setAt() with an appropriate
490 value. Return true to indicate success, or false to signify
491 failure.
492
493 \sa fetch(), fetchLast()
494*/
495
496/*!
497 \fn bool QSqlResult::fetchLast()
498
499 Positions the result to the last record (last row) in the result.
500
501 This function is only called if the result is in an active state.
502 Derived classes must reimplement this function and position the
503 result to the last record, and call setAt() with an appropriate
504 value. Return true to indicate success, or false to signify
505 failure.
506
507 \sa fetch(), fetchFirst()
508*/
509
510/*!
511 Positions the result to the next available record (row) in the
512 result.
513
514 This function is only called if the result is in an active
515 state. The default implementation calls fetch() with the next
516 index. Derived classes can reimplement this function and position
517 the result to the next record in some other way, and call setAt()
518 with an appropriate value. Return true to indicate success, or
519 false to signify failure.
520
521 \sa fetch(), fetchPrevious()
522*/
523
524bool QSqlResult::fetchNext()
525{
526 return fetch(at() + 1);
527}
528
529/*!
530 Positions the result to the previous record (row) in the result.
531
532 This function is only called if the result is in an active state.
533 The default implementation calls fetch() with the previous index.
534 Derived classes can reimplement this function and position the
535 result to the next record in some other way, and call setAt()
536 with an appropriate value. Return true to indicate success, or
537 false to signify failure.
538*/
539
540bool QSqlResult::fetchPrevious()
541{
542 return fetch(at() - 1);
543}
544
545/*!
546 Returns true if you can only scroll forward through the result
547 set; otherwise returns false.
548
549 \sa setForwardOnly()
550*/
551bool QSqlResult::isForwardOnly() const
552{
553 return d->forwardOnly;
554}
555
556/*!
557 Sets forward only mode to \a forward. If \a forward is true, only
558 fetchNext() is allowed for navigating the results. Forward only
559 mode needs much less memory since results do not have to be
560 cached. By default, this feature is disabled.
561
562 Setting forward only to false is a suggestion to the database engine,
563 which has the final say on whether a result set is forward only or
564 scrollable. isForwardOnly() will always return the correct status of
565 the result set.
566
567 \note Calling setForwardOnly after execution of the query will result
568 in unexpected results at best, and crashes at worst.
569
570 \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly()
571*/
572void QSqlResult::setForwardOnly(bool forward)
573{
574 d->forwardOnly = forward;
575}
576
577/*!
578 Prepares the given \a query, using the underlying database
579 functionality where possible. Returns true if the query is
580 prepared successfully; otherwise returns false.
581
582 \sa prepare()
583*/
584bool QSqlResult::savePrepare(const QString& query)
585{
586 if (!driver())
587 return false;
588 d->clear();
589 d->sql = query;
590 if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
591 return prepare(query);
592
593 if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) {
594 // parse the query to memorize parameter location
595 d->namedToPositionalBinding();
596 d->executedQuery = d->positionalToNamedBinding();
597 } else {
598 d->executedQuery = d->namedToPositionalBinding();
599 }
600 return prepare(d->executedQuery);
601}
602
603/*!
604 Prepares the given \a query for execution; the query will normally
605 use placeholders so that it can be executed repeatedly. Returns
606 true if the query is prepared successfully; otherwise returns false.
607
608 \sa exec()
609*/
610bool QSqlResult::prepare(const QString& query)
611{
612 int n = query.size();
613
614 bool inQuote = false;
615 int i = 0;
616
617 while (i < n) {
618 QChar ch = query.at(i);
619 if (ch == QLatin1Char(':') && !inQuote
620 && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
621 && (i < n - 1 && qIsAlnum(query.at(i + 1)))) {
622 int pos = i + 2;
623 while (pos < n && qIsAlnum(query.at(pos)))
624 ++pos;
625
626 d->holders.append(QHolder(query.mid(i, pos - i), i));
627 i = pos;
628 } else {
629 if (ch == QLatin1Char('\''))
630 inQuote = !inQuote;
631 ++i;
632 }
633 }
634 d->sql = query;
635 return true; // fake prepares should always succeed
636}
637
638/*!
639 Executes the query, returning true if successful; otherwise returns
640 false.
641
642 \sa prepare()
643*/
644bool QSqlResult::exec()
645{
646 bool ret;
647 // fake preparation - just replace the placeholders..
648 QString query = lastQuery();
649 if (d->binds == NamedBinding) {
650 int i;
651 QVariant val;
652 QString holder;
653 for (i = d->holders.count() - 1; i >= 0; --i) {
654 holder = d->holders.at(i).holderName;
655 val = d->values.value(d->indexes.value(holder));
656 QSqlField f(QLatin1String(""), val.type());
657 f.setValue(val);
658 query = query.replace(d->holders.at(i).holderPos,
659 holder.length(), driver()->formatValue(f));
660 }
661 } else {
662 QString val;
663 int i = 0;
664 int idx = 0;
665 for (idx = 0; idx < d->values.count(); ++idx) {
666 i = query.indexOf(QLatin1Char('?'), i);
667 if (i == -1)
668 continue;
669 QVariant var = d->values.value(idx);
670 QSqlField f(QLatin1String(""), var.type());
671 if (var.isNull())
672 f.clear();
673 else
674 f.setValue(var);
675 val = driver()->formatValue(f);
676 query = query.replace(i, 1, driver()->formatValue(f));
677 i += val.length();
678 }
679 }
680
681 // have to retain the original query with placeholders
682 QString orig = lastQuery();
683 ret = reset(query);
684 d->executedQuery = query;
685 setQuery(orig);
686 d->resetBindCount();
687 return ret;
688}
689
690/*!
691 Binds the value \a val of parameter type \a paramType to position \a index
692 in the current record (row).
693
694 \sa addBindValue()
695*/
696void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
697{
698 d->binds = PositionalBinding;
699 d->indexes[qFieldSerial(index)] = index;
700 if (d->values.count() <= index)
701 d->values.resize(index + 1);
702 d->values[index] = val;
703 if (paramType != QSql::In || !d->types.isEmpty())
704 d->types[index] = paramType;
705}
706
707/*!
708 \overload
709
710 Binds the value \a val of parameter type \a paramType to the \a
711 placeholder name in the current record (row).
712
713 Values cannot be bound to multiple locations in the query, eg:
714 \code
715 INSERT INTO testtable (id, name, samename) VALUES (:id, :name, :name)
716 \endcode
717 Binding to name will bind to the first :name, but not the second.
718
719 \note Binding an undefined placeholder will result in undefined behavior.
720
721 \sa QSqlQuery::bindValue()
722*/
723void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
724 QSql::ParamType paramType)
725{
726 d->binds = NamedBinding;
727 // if the index has already been set when doing emulated named
728 // bindings - don't reset it
729 int idx = d->indexes.value(placeholder, -1);
730 if (idx >= 0) {
731 if (d->values.count() <= idx)
732 d->values.resize(idx + 1);
733 d->values[idx] = val;
734 } else {
735 d->values.append(val);
736 idx = d->values.count() - 1;
737 d->indexes[placeholder] = idx;
738 }
739
740 if (paramType != QSql::In || !d->types.isEmpty())
741 d->types[idx] = paramType;
742}
743
744/*!
745 Binds the value \a val of parameter type \a paramType to the next
746 available position in the current record (row).
747
748 \sa bindValue()
749*/
750void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
751{
752 d->binds = PositionalBinding;
753 bindValue(d->bindCount, val, paramType);
754 ++d->bindCount;
755}
756
757/*!
758 Returns the value bound at position \a index in the current record
759 (row).
760
761 \sa bindValue(), boundValues()
762*/
763QVariant QSqlResult::boundValue(int index) const
764{
765 return d->values.value(index);
766}
767
768/*!
769 \overload
770
771 Returns the value bound by the given \a placeholder name in the
772 current record (row).
773
774 \sa bindValueType()
775*/
776QVariant QSqlResult::boundValue(const QString& placeholder) const
777{
778 int idx = d->indexes.value(placeholder, -1);
779 return d->values.value(idx);
780}
781
782/*!
783 Returns the parameter type for the value bound at position \a index.
784
785 \sa boundValue()
786*/
787QSql::ParamType QSqlResult::bindValueType(int index) const
788{
789 return d->types.value(index, QSql::In);
790}
791
792/*!
793 \overload
794
795 Returns the parameter type for the value bound with the given \a
796 placeholder name.
797*/
798QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
799{
800 return d->types.value(d->indexes.value(placeholder, -1), QSql::In);
801}
802
803/*!
804 Returns the number of bound values in the result.
805
806 \sa boundValues()
807*/
808int QSqlResult::boundValueCount() const
809{
810 return d->values.count();
811}
812
813/*!
814 Returns a vector of the result's bound values for the current
815 record (row).
816
817 \sa boundValueCount()
818*/
819QVector<QVariant>& QSqlResult::boundValues() const
820{
821 return d->values;
822}
823
824/*!
825 Returns the binding syntax used by prepared queries.
826*/
827QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const
828{
829 return d->binds;
830}
831
832/*!
833 Clears the entire result set and releases any associated
834 resources.
835*/
836void QSqlResult::clear()
837{
838 d->clear();
839}
840
841/*!
842 Returns the query that was actually executed. This may differ from
843 the query that was passed, for example if bound values were used
844 with a prepared query and the underlying database doesn't support
845 prepared queries.
846
847 \sa exec(), setQuery()
848*/
849QString QSqlResult::executedQuery() const
850{
851 return d->executedQuery;
852}
853
854void QSqlResult::resetBindCount()
855{
856 d->resetBindCount();
857}
858
859/*!
860 Returns the name of the bound value at position \a index in the
861 current record (row).
862
863 \sa boundValue()
864*/
865QString QSqlResult::boundValueName(int index) const
866{
867 return d->holderAt(index);
868}
869
870/*!
871 Returns true if at least one of the query's bound values is a \c
872 QSql::Out or a QSql::InOut; otherwise returns false.
873
874 \sa bindValueType()
875*/
876bool QSqlResult::hasOutValues() const
877{
878 if (d->types.isEmpty())
879 return false;
880 QHash<int, QSql::ParamType>::ConstIterator it;
881 for (it = d->types.constBegin(); it != d->types.constEnd(); ++it) {
882 if (it.value() != QSql::In)
883 return true;
884 }
885 return false;
886}
887
888/*!
889 Returns the current record if the query is active; otherwise
890 returns an empty QSqlRecord.
891
892 The default implementation always returns an empty QSqlRecord.
893
894 \sa isActive()
895*/
896QSqlRecord QSqlResult::record() const
897{
898 return QSqlRecord();
899}
900
901/*!
902 Returns the object ID of the most recent inserted row if the
903 database supports it.
904 An invalid QVariant will be returned if the query did not
905 insert any value or if the database does not report the id back.
906 If more than one row was touched by the insert, the behavior is
907 undefined.
908
909 Note that for Oracle databases the row's ROWID will be returned,
910 while for MySQL databases the row's auto-increment field will
911 be returned.
912
913 \sa QSqlDriver::hasFeature()
914*/
915QVariant QSqlResult::lastInsertId() const
916{
917 return QVariant();
918}
919
920/*! \internal
921*/
922void QSqlResult::virtual_hook(int, void *)
923{
924}
925
926/*! \internal
927 \since 4.2
928
929 Executes a prepared query in batch mode if the driver supports it,
930 otherwise emulates a batch execution using bindValue() and exec().
931 QSqlDriver::hasFeature() can be used to find out whether a driver
932 supports batch execution.
933
934 Batch execution can be faster for large amounts of data since it
935 reduces network roundtrips.
936
937 For batch executions, bound values have to be provided as lists
938 of variants (QVariantList).
939
940 Each list must contain values of the same type. All lists must
941 contain equal amount of values (rows).
942
943 NULL values are passed in as typed QVariants, for example
944 \c {QVariant(QVariant::Int)} for an integer NULL value.
945
946 Example:
947
948 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 0
949
950 Here, we insert two rows into a SQL table, with each row containing three values.
951
952 \sa exec(), QSqlDriver::hasFeature()
953*/
954bool QSqlResult::execBatch(bool arrayBind)
955{
956 if (driver()->hasFeature(QSqlDriver::BatchOperations)) {
957 virtual_hook(BatchOperation, &arrayBind);
958 d->resetBindCount();
959 return d->error.type() == QSqlError::NoError;
960 } else {
961 QVector<QVariant> values = d->values;
962 if (values.count() == 0)
963 return false;
964 for (int i = 0; i < values.at(0).toList().count(); ++i) {
965 for (int j = 0; j < values.count(); ++j)
966 bindValue(j, values.at(j).toList().at(i), QSql::In);
967 if (!exec())
968 return false;
969 }
970 return true;
971 }
972 return false;
973}
974
975/*! \internal
976 */
977void QSqlResult::detachFromResultSet()
978{
979 if (driver()->hasFeature(QSqlDriver::FinishQuery)
980 || driver()->hasFeature(QSqlDriver::SimpleLocking))
981 virtual_hook(DetachFromResultSet, 0);
982}
983
984/*! \internal
985 */
986void QSqlResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
987{
988 d->precisionPolicy = policy;
989 virtual_hook(SetNumericalPrecision, &policy);
990}
991
992/*! \internal
993 */
994QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
995{
996 return d->precisionPolicy;
997}
998
999/*! \internal
1000*/
1001bool QSqlResult::nextResult()
1002{
1003 if (driver()->hasFeature(QSqlDriver::MultipleResultSets)) {
1004 bool result = false;
1005 virtual_hook(NextResult, &result);
1006 return result;
1007 }
1008 return false;
1009}
1010
1011/*!
1012 Returns the low-level database handle for this result set
1013 wrapped in a QVariant or an invalid QVariant if there is no handle.
1014
1015 \warning Use this with uttermost care and only if you know what you're doing.
1016
1017 \warning The handle returned here can become a stale pointer if the result
1018 is modified (for example, if you clear it).
1019
1020 \warning The handle can be NULL if the result was not executed yet.
1021
1022 The handle returned here is database-dependent, you should query the type
1023 name of the variant before accessing it.
1024
1025 This example retrieves the handle for a sqlite result:
1026
1027 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 1
1028
1029 This snippet returns the handle for PostgreSQL or MySQL:
1030
1031 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 2
1032
1033 \sa QSqlDriver::handle()
1034*/
1035QVariant QSqlResult::handle() const
1036{
1037 return QVariant();
1038}
1039
1040QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.