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

Last change on this file since 636 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 25.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [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#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::fromUtf16(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 \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly()
568*/
569void QSqlResult::setForwardOnly(bool forward)
570{
571 d->forwardOnly = forward;
572}
573
574/*!
575 Prepares the given \a query, using the underlying database
576 functionality where possible. Returns true if the query is
577 prepared successfully; otherwise returns false.
578
579 \sa prepare()
580*/
581bool QSqlResult::savePrepare(const QString& query)
582{
583 if (!driver())
584 return false;
585 d->clear();
586 d->sql = query;
587 if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
588 return prepare(query);
589
590 if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) {
591 // parse the query to memorize parameter location
592 d->namedToPositionalBinding();
593 d->executedQuery = d->positionalToNamedBinding();
594 } else {
595 d->executedQuery = d->namedToPositionalBinding();
596 }
597 return prepare(d->executedQuery);
598}
599
600/*!
601 Prepares the given \a query for execution; the query will normally
602 use placeholders so that it can be executed repeatedly. Returns
603 true if the query is prepared successfully; otherwise returns false.
604
605 \sa exec()
606*/
607bool QSqlResult::prepare(const QString& query)
608{
609 int n = query.size();
610
611 bool inQuote = false;
612 int i = 0;
613
614 while (i < n) {
615 QChar ch = query.at(i);
616 if (ch == QLatin1Char(':') && !inQuote
617 && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
618 && (i < n - 1 && qIsAlnum(query.at(i + 1)))) {
619 int pos = i + 2;
620 while (pos < n && qIsAlnum(query.at(pos)))
621 ++pos;
622
623 d->holders.append(QHolder(query.mid(i, pos - i), i));
624 i = pos;
625 } else {
626 if (ch == QLatin1Char('\''))
627 inQuote = !inQuote;
628 ++i;
629 }
630 }
631 d->sql = query;
632 return true; // fake prepares should always succeed
633}
634
635/*!
636 Executes the query, returning true if successful; otherwise returns
637 false.
638
639 \sa prepare()
640*/
641bool QSqlResult::exec()
642{
643 bool ret;
644 // fake preparation - just replace the placeholders..
645 QString query = lastQuery();
646 if (d->binds == NamedBinding) {
647 int i;
648 QVariant val;
649 QString holder;
650 for (i = d->holders.count() - 1; i >= 0; --i) {
651 holder = d->holders.at(i).holderName;
652 val = d->values.value(d->indexes.value(holder));
653 QSqlField f(QLatin1String(""), val.type());
654 f.setValue(val);
655 query = query.replace(d->holders.at(i).holderPos,
656 holder.length(), driver()->formatValue(f));
657 }
658 } else {
659 QString val;
660 int i = 0;
661 int idx = 0;
662 for (idx = 0; idx < d->values.count(); ++idx) {
663 i = query.indexOf(QLatin1Char('?'), i);
664 if (i == -1)
665 continue;
666 QVariant var = d->values.value(idx);
667 QSqlField f(QLatin1String(""), var.type());
668 if (var.isNull())
669 f.clear();
670 else
671 f.setValue(var);
672 val = driver()->formatValue(f);
673 query = query.replace(i, 1, driver()->formatValue(f));
674 i += val.length();
675 }
676 }
677
678 // have to retain the original query with placeholders
679 QString orig = lastQuery();
680 ret = reset(query);
681 d->executedQuery = query;
682 setQuery(orig);
683 d->resetBindCount();
684 return ret;
685}
686
687/*!
688 Binds the value \a val of parameter type \a paramType to position \a index
689 in the current record (row).
690
691 \sa addBindValue()
692*/
693void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
694{
695 d->binds = PositionalBinding;
696 d->indexes[qFieldSerial(index)] = index;
697 if (d->values.count() <= index)
698 d->values.resize(index + 1);
699 d->values[index] = val;
700 if (paramType != QSql::In || !d->types.isEmpty())
701 d->types[index] = paramType;
702}
703
704/*!
705 \overload
706
707 Binds the value \a val of parameter type \a paramType to the \a
708 placeholder name in the current record (row).
709
710 Note that binding an undefined placeholder will result in undefined behavior.
711*/
712void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
713 QSql::ParamType paramType)
714{
715 d->binds = NamedBinding;
716 // if the index has already been set when doing emulated named
717 // bindings - don't reset it
718 int idx = d->indexes.value(placeholder, -1);
719 if (idx >= 0) {
720 if (d->values.count() <= idx)
721 d->values.resize(idx + 1);
722 d->values[idx] = val;
723 } else {
724 d->values.append(val);
725 idx = d->values.count() - 1;
726 d->indexes[placeholder] = idx;
727 }
728
729 if (paramType != QSql::In || !d->types.isEmpty())
730 d->types[idx] = paramType;
731}
732
733/*!
734 Binds the value \a val of parameter type \a paramType to the next
735 available position in the current record (row).
736
737 \sa bindValue()
738*/
739void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
740{
741 d->binds = PositionalBinding;
742 bindValue(d->bindCount, val, paramType);
743 ++d->bindCount;
744}
745
746/*!
747 Returns the value bound at position \a index in the current record
748 (row).
749
750 \sa bindValue(), boundValues()
751*/
752QVariant QSqlResult::boundValue(int index) const
753{
754 return d->values.value(index);
755}
756
757/*!
758 \overload
759
760 Returns the value bound by the given \a placeholder name in the
761 current record (row).
762
763 \sa bindValueType()
764*/
765QVariant QSqlResult::boundValue(const QString& placeholder) const
766{
767 int idx = d->indexes.value(placeholder, -1);
768 return d->values.value(idx);
769}
770
771/*!
772 Returns the parameter type for the value bound at position \a index.
773
774 \sa boundValue()
775*/
776QSql::ParamType QSqlResult::bindValueType(int index) const
777{
778 return d->types.value(index, QSql::In);
779}
780
781/*!
782 \overload
783
784 Returns the parameter type for the value bound with the given \a
785 placeholder name.
786*/
787QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
788{
789 return d->types.value(d->indexes.value(placeholder, -1), QSql::In);
790}
791
792/*!
793 Returns the number of bound values in the result.
794
795 \sa boundValues()
796*/
797int QSqlResult::boundValueCount() const
798{
799 return d->values.count();
800}
801
802/*!
803 Returns a vector of the result's bound values for the current
804 record (row).
805
806 \sa boundValueCount()
807*/
808QVector<QVariant>& QSqlResult::boundValues() const
809{
810 return d->values;
811}
812
813/*!
814 Returns the binding syntax used by prepared queries.
815*/
816QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const
817{
818 return d->binds;
819}
820
821/*!
822 Clears the entire result set and releases any associated
823 resources.
824*/
825void QSqlResult::clear()
826{
827 d->clear();
828}
829
830/*!
831 Returns the query that was actually executed. This may differ from
832 the query that was passed, for example if bound values were used
833 with a prepared query and the underlying database doesn't support
834 prepared queries.
835
836 \sa exec(), setQuery()
837*/
838QString QSqlResult::executedQuery() const
839{
840 return d->executedQuery;
841}
842
843void QSqlResult::resetBindCount()
844{
845 d->resetBindCount();
846}
847
848/*!
849 Returns the name of the bound value at position \a index in the
850 current record (row).
851
852 \sa boundValue()
853*/
854QString QSqlResult::boundValueName(int index) const
855{
856 return d->holderAt(index);
857}
858
859/*!
860 Returns true if at least one of the query's bound values is a \c
861 QSql::Out or a QSql::InOut; otherwise returns false.
862
863 \sa bindValueType()
864*/
865bool QSqlResult::hasOutValues() const
866{
867 if (d->types.isEmpty())
868 return false;
869 QHash<int, QSql::ParamType>::ConstIterator it;
870 for (it = d->types.constBegin(); it != d->types.constEnd(); ++it) {
871 if (it.value() != QSql::In)
872 return true;
873 }
874 return false;
875}
876
877/*!
878 Returns the current record if the query is active; otherwise
879 returns an empty QSqlRecord.
880
881 The default implementation always returns an empty QSqlRecord.
882
883 \sa isActive()
884*/
885QSqlRecord QSqlResult::record() const
886{
887 return QSqlRecord();
888}
889
890/*!
891 Returns the object ID of the most recent inserted row if the
892 database supports it.
893 An invalid QVariant will be returned if the query did not
894 insert any value or if the database does not report the id back.
895 If more than one row was touched by the insert, the behavior is
896 undefined.
897
898 Note that for Oracle databases the row's ROWID will be returned,
899 while for MySQL databases the row's auto-increment field will
900 be returned.
901
902 \sa QSqlDriver::hasFeature()
903*/
904QVariant QSqlResult::lastInsertId() const
905{
906 return QVariant();
907}
908
909/*! \internal
910*/
911void QSqlResult::virtual_hook(int, void *)
912{
913}
914
915/*! \internal
916 \since 4.2
917
918 Executes a prepared query in batch mode if the driver supports it,
919 otherwise emulates a batch execution using bindValue() and exec().
920 QSqlDriver::hasFeature() can be used to find out whether a driver
921 supports batch execution.
922
923 Batch execution can be faster for large amounts of data since it
924 reduces network roundtrips.
925
926 For batch executions, bound values have to be provided as lists
927 of variants (QVariantList).
928
929 Each list must contain values of the same type. All lists must
930 contain equal amount of values (rows).
931
932 NULL values are passed in as typed QVariants, for example
933 \c {QVariant(QVariant::Int)} for an integer NULL value.
934
935 Example:
936
937 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 0
938
939 Here, we insert two rows into a SQL table, with each row containing three values.
940
941 \sa exec(), QSqlDriver::hasFeature()
942*/
943bool QSqlResult::execBatch(bool arrayBind)
944{
945 if (driver()->hasFeature(QSqlDriver::BatchOperations)) {
946 virtual_hook(BatchOperation, &arrayBind);
947 d->resetBindCount();
948 return d->error.type() == QSqlError::NoError;
949 } else {
950 QVector<QVariant> values = d->values;
951 if (values.count() == 0)
952 return false;
953 for (int i = 0; i < values.at(0).toList().count(); ++i) {
954 for (int j = 0; j < values.count(); ++j)
955 bindValue(j, values.at(j).toList().at(i), QSql::In);
956 if (!exec())
957 return false;
958 }
959 return true;
960 }
961 return false;
962}
963
964/*! \internal
965 */
966void QSqlResult::detachFromResultSet()
967{
968 if (driver()->hasFeature(QSqlDriver::FinishQuery)
969 || driver()->hasFeature(QSqlDriver::SimpleLocking))
970 virtual_hook(DetachFromResultSet, 0);
971}
972
973/*! \internal
974 */
975void QSqlResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
976{
977 d->precisionPolicy = policy;
978 virtual_hook(SetNumericalPrecision, &policy);
979}
980
981/*! \internal
982 */
983QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
984{
985 return d->precisionPolicy;
986}
987
988/*! \internal
989*/
990bool QSqlResult::nextResult()
991{
992 if (driver()->hasFeature(QSqlDriver::MultipleResultSets)) {
993 bool result = false;
994 virtual_hook(NextResult, &result);
995 return result;
996 }
997 return false;
998}
999
1000/*!
1001 Returns the low-level database handle for this result set
1002 wrapped in a QVariant or an invalid QVariant if there is no handle.
1003
1004 \warning Use this with uttermost care and only if you know what you're doing.
1005
1006 \warning The handle returned here can become a stale pointer if the result
1007 is modified (for example, if you clear it).
1008
1009 \warning The handle can be NULL if the result was not executed yet.
1010
1011 The handle returned here is database-dependent, you should query the type
1012 name of the variant before accessing it.
1013
1014 This example retrieves the handle for a sqlite result:
1015
1016 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 1
1017
1018 This snippet returns the handle for PostgreSQL or MySQL:
1019
1020 \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 2
1021
1022 \sa QSqlDriver::handle()
1023*/
1024QVariant QSqlResult::handle() const
1025{
1026 return QVariant();
1027}
1028
1029QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.