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