Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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
18
19using namespace Qt::StringLiterals;
20
25
27{
28 return QString(":%1"_L1).arg(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
39{
41 return query;
42
43 const qsizetype n = query.size();
44
46 result.reserve(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 + 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'?') {
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
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
87 query.trimmed().startsWith("EXECUTE BLOCK"_L1, Qt::CaseInsensitive))
88 return query;
89
90 const qsizetype n = query.size();
91
93 result.reserve(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 + 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 - 1) != u':')
118 && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
119 int pos = i + 2;
120 while (pos < n && qIsAlnum(query.at(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
129 QString holder(query.mid(i, pos - i));
130 indexes[holder].append(count++);
131 holders.append(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(holders.size());
145 return result;
146}
147
193{
194 d_ptr = new QSqlResultPrivate(this, db);
195 Q_D(QSqlResult);
196 if (d->sqldriver)
197 setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy());
198}
199
203 : d_ptr(&dd)
204{
205 Q_D(QSqlResult);
206 if (d->sqldriver)
207 setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy());
208}
209
215{
216 Q_D(QSqlResult);
217 delete d;
218}
219
228{
229 Q_D(QSqlResult);
230 d->sql = query;
231}
232
241{
242 Q_D(const QSqlResult);
243 return d->sql;
244}
245
253int QSqlResult::at() const
254{
255 Q_D(const QSqlResult);
256 return d->idx;
257}
258
259
269{
270 Q_D(const QSqlResult);
271 return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
272}
273
287{
288 Q_D(const QSqlResult);
289 return d->active;
290}
291
300{
301 Q_D(QSqlResult);
302 d->idx = index;
303}
304
305
316{
317 Q_D(QSqlResult);
318 d->isSel = select;
319}
320
329{
330 Q_D(const QSqlResult);
331 return d->isSel;
332}
333
340{
341 Q_D(const QSqlResult);
342 return d->sqldriver;
343}
344
345
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
370{
371 Q_D(QSqlResult);
372 d->error = error;
373}
374
375
381{
382 Q_D(const QSqlResult);
383 return d->error;
384}
385
489{
490 return fetch(at() + 1);
491}
492
505{
506 return fetch(at() - 1);
507}
508
516{
517 Q_D(const QSqlResult);
518 return d->forwardOnly;
519}
520
546{
547 Q_D(QSqlResult);
548 d->forwardOnly = forward;
549}
550
561{
562 Q_D(QSqlResult);
563 if (!driver())
564 return false;
565 d->clear();
566 d->sql = query;
568 return prepare(query);
569
570 // parse the query to memorize parameter location
571 d->executedQuery = d->namedToPositionalBinding(query);
572
574 d->executedQuery = d->positionalToNamedBinding(query);
575
576 return prepare(d->executedQuery);
577}
578
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
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
631{
632 Q_D(QSqlResult);
633 bool ret;
634 // fake preparation - just replace the placeholders..
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(d->indexes.value(holder).value(0,-1));
640 QSqlField f(""_L1, val.metaType());
642 f.setValue(QVariant());
643 else
644 f.setValue(val);
645 query = query.replace(d->holders.at(i).holderPos,
646 holder.size(), driver()->formatValue(f));
647 }
648 } else {
649 qsizetype i = 0;
650 for (const QVariant &var : std::as_const(d->values)) {
651 i = query.indexOf(u'?', i);
652 if (i == -1)
653 continue;
654 QSqlField f(""_L1, var.metaType());
656 f.clear();
657 else
658 f.setValue(var);
659 const QString val = driver()->formatValue(f);
660 query = query.replace(i, 1, val);
661 i += val.size();
662 }
663 }
664
665 // have to retain the original query with placeholders
666 QString orig = lastQuery();
667 ret = reset(query);
668 d->executedQuery = query;
669 setQuery(orig);
670 d->resetBindCount();
671 return ret;
672}
673
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(index)];
685 if (!indexes.contains(index))
686 indexes.append(index);
687 if (d->values.size() <= 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
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(placeholder);
712 for (int idx : indexes) {
713 if (d->values.size() <= idx)
714 d->values.resize(idx + 1);
715 d->values[idx] = val;
716 if (paramType != QSql::In || !d->types.isEmpty())
717 d->types[idx] = paramType;
718 }
719}
720
727void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
728{
729 Q_D(QSqlResult);
730 d->binds = PositionalBinding;
731 bindValue(d->bindCount, val, paramType);
732 ++d->bindCount;
733}
734
742{
743 Q_D(const QSqlResult);
744 return d->values.value(index);
745}
746
755QVariant QSqlResult::boundValue(const QString& placeholder) const
756{
757 Q_D(const QSqlResult);
758 const QList<int> indexes = d->indexes.value(placeholder);
759 return d->values.value(indexes.value(0,-1));
760}
761
767QSql::ParamType QSqlResult::bindValueType(int index) const
768{
769 Q_D(const QSqlResult);
770 return d->types.value(index, QSql::In);
771}
772
779QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
780{
781 Q_D(const QSqlResult);
782 return d->types.value(d->indexes.value(placeholder).value(0,-1), QSql::In);
783}
784
791{
792 Q_D(const QSqlResult);
793 return d->values.size();
794}
795
803{
804 Q_D(const QSqlResult);
805 return d->values;
806}
807
817{
818 Q_D(QSqlResult);
819 return d->values;
820}
821
822
827{
828 Q_D(const QSqlResult);
829 return d->binds;
830}
831
837{
838 Q_D(QSqlResult);
839 d->clear();
840}
841
851{
852 Q_D(const QSqlResult);
853 return d->executedQuery;
854}
855
860{
861 Q_D(QSqlResult);
862 d->resetBindCount();
863}
864
871{
872 Q_D(const QSqlResult);
873 QList<QString> ret;
874 for (const QHolder &holder : std::as_const(d->holders))
875 ret.push_back(holder.holderName);
876 return ret;
877}
878
886{
887 Q_D(const QSqlResult);
888 return d->holderAt(index);
889}
890
898{
899 Q_D(const QSqlResult);
900 if (d->types.isEmpty())
901 return false;
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
919{
920 return QSqlRecord();
921}
922
938{
939 return QVariant();
940}
941
945{
946}
947
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(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(j, values.at(j).toList().at(i), QSql::In);
987 if (!exec())
988 return false;
989 }
990 return true;
991}
992
998
1006
1010{
1011 Q_D(const QSqlResult);
1012 return d->precisionPolicy;
1013}
1014
1018{
1019 Q_D(QSqlResult);
1020 d->positionalBindingEnabled = enable;
1021}
1022
1026{
1027 Q_D(const QSqlResult);
1028 return d->positionalBindingEnabled;
1029}
1030
1031
1035{
1036 return false;
1037}
1038
1068{
1069 return QVariant();
1070}
1071
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore \reentrant
Definition qdatetime.h:29
\inmodule QtCore
Definition qhash.h:1145
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:26
virtual QString formatValue(const QSqlField &field, bool trimStrings=false) const
Returns a string representation of the field value for the database.
@ PreparedQueries
Definition qsqldriver.h:33
@ NamedPlaceholders
Definition qsqldriver.h:34
DbmsType dbmsType() const
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
The QSqlField class manipulates the fields in SQL database tables and views.
Definition qsqlfield.h:19
The QSqlRecord class encapsulates a database record.
Definition qsqlrecord.h:20
QString holderAt(int index) const
QString namedToPositionalBinding(const QString &query)
QHolderVector holders
QString positionalToNamedBinding(const QString &query) const
static bool isVariantNull(const QVariant &variant)
QPointer< QSqlDriver > sqldriver
virtual QString fieldSerial(qsizetype) const
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
Definition qsqlresult.h:22
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false.
virtual QVariant lastInsertId() const
Returns the object ID of the most recent inserted row if the database supports it.
QString executedQuery() const
Returns the query that was actually executed.
QSql::ParamType bindValueType(const QString &placeholder) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void clear()
Clears the entire result set and releases any associated resources.
virtual bool execBatch(bool arrayBind=false)
virtual void virtual_hook(int id, void *data)
virtual void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
virtual void detachFromResultSet()
bool isPositionalBindingEnabled() const
int at() const
Returns the current (zero-based) row position of the result.
virtual bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
BindingSyntax
This enum type specifies the different syntaxes for specifying placeholders in prepared queries.
Definition qsqlresult.h:32
@ PositionalBinding
Definition qsqlresult.h:33
QVariant boundValue(const QString &placeholder) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
virtual bool exec()
Executes the query, returning true if successful; otherwise returns false.
void setPositionalBindingEnabled(bool enable)
void addBindValue(const QVariant &val, QSql::ParamType type)
Binds the value val of parameter type paramType to the next available position in the current record ...
virtual ~QSqlResult()
Destroys the object and frees any allocated resources.
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
QString lastQuery() const
Returns the current SQL query text, or an empty string if there isn't one.
bool hasOutValues() const
Returns true if at least one of the query's bound values is a QSql::Out or a QSql::InOut; otherwise r...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
virtual bool fetchPrevious()
Positions the result to the previous record (row) in the result.
virtual bool nextResult()
virtual bool fetch(int i)=0
Positions the result to an arbitrary (zero-based) row index.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
virtual QVariant handle() const
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
virtual bool fetchNext()
Positions the result to the next available record (row) in the result.
void resetBindCount()
Resets the number of bind parameters.
QSqlResult(const QSqlDriver *db)
Creates a QSqlResult using database driver db.
virtual bool savePrepare(const QString &sqlquery)
Prepares the given query, using the underlying database functionality where possible.
QSqlError lastError() const
Returns the last error associated with the result.
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
virtual QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
BindingSyntax bindingSyntax() const
Returns the binding syntax used by prepared queries.
int boundValueCount() const
Returns the number of bound values in the result.
virtual void setQuery(const QString &query)
Sets the current query for the result to query.
const QSqlDriver * driver() const
Returns the driver associated with the result.
QString boundValueName(int pos) const
Returns the name of the bound value at position index in the current record (row).
bool isValid() const
Returns true if the result is positioned on a valid record (that is, the result is not positioned bef...
QStringList boundValueNames() const
Returns the names of all bound values.
virtual void setForwardOnly(bool forward)
Sets forward only mode to forward.
virtual void bindValue(int pos, const QVariant &val, QSql::ParamType type)
Binds the value val of parameter type paramType to position index in the current record (row).
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
QSqlResultPrivate * d_ptr
Definition qsqlresult.h:105
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
\inmodule QtCore \reentrant
Definition qdatetime.h:215
\inmodule QtCore
Definition quuid.h:31
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
int typeId() const
Returns the storage type of the value stored in the variant.
Definition qvariant.h:340
bool isNull() const
Returns true if this is a null variant, false otherwise.
QMetaType metaType() const
const void * constData() const
Definition qvariant.h:451
QSet< QString >::iterator it
@ AfterLastRow
Definition qtsqlglobal.h:22
@ BeforeFirstRow
Definition qtsqlglobal.h:21
NumericalPrecisionPolicy
Definition qtsqlglobal.h:43
Combined button and popup list for selecting options.
@ CaseInsensitive
DBusConnection const char DBusError * error
static bool hasFeature(const QDockWidgetPrivate *priv, QDockWidget::DockWidgetFeature feature)
return ret
GLenum GLsizei GLsizei GLint * values
[15]
GLuint index
[2]
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLboolean enable
GLfloat n
GLboolean reset
GLenum query
GLuint GLfloat * val
GLuint64EXT * result
[6]
static bool qIsAlnum(QChar ch)
#define Q_UNUSED(x)
#define QT6_IMPL_NEW_OVERLOAD
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
QVariant variant
[1]
QMimeDatabase db
[0]
selection select(topLeft, bottomRight)
QSizePolicy policy
QString holderName