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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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