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