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

source code of qtbase/src/sql/kernel/qsqlresult.cpp