Qt 6.x
The Qt SDK
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
22{
24}
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{
40 const qsizetype n = query.size();
41
43 result.reserve(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 + 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'?') {
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
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
84 query.trimmed().startsWith("EXECUTE BLOCK"_L1, Qt::CaseInsensitive))
85 return query;
86
87 const qsizetype n = query.size();
88
90 result.reserve(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 + 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 - 1) != u':')
114 && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
115 int pos = i + 2;
116 while (pos < n && qIsAlnum(query.at(pos)))
117 ++pos;
118 QString holder(query.mid(i, pos - i));
119 indexes[holder].append(count++);
120 holders.append(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(holders.size());
135 return result;
136}
137
183{
184 d_ptr = new QSqlResultPrivate(this, db);
185 Q_D(QSqlResult);
186 if (d->sqldriver)
187 setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy());
188}
189
193 : d_ptr(&dd)
194{
195 Q_D(QSqlResult);
196 if (d->sqldriver)
197 setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy());
198}
199
205{
206 Q_D(QSqlResult);
207 delete d;
208}
209
218{
219 Q_D(QSqlResult);
220 d->sql = query;
221}
222
231{
232 Q_D(const QSqlResult);
233 return d->sql;
234}
235
243int QSqlResult::at() const
244{
245 Q_D(const QSqlResult);
246 return d->idx;
247}
248
249
259{
260 Q_D(const QSqlResult);
261 return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
262}
263
277{
278 Q_D(const QSqlResult);
279 return d->active;
280}
281
290{
291 Q_D(QSqlResult);
292 d->idx = index;
293}
294
295
306{
307 Q_D(QSqlResult);
308 d->isSel = select;
309}
310
319{
320 Q_D(const QSqlResult);
321 return d->isSel;
322}
323
330{
331 Q_D(const QSqlResult);
332 return d->sqldriver;
333}
334
335
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
360{
361 Q_D(QSqlResult);
362 d->error = error;
363}
364
365
371{
372 Q_D(const QSqlResult);
373 return d->error;
374}
375
479{
480 return fetch(at() + 1);
481}
482
495{
496 return fetch(at() - 1);
497}
498
506{
507 Q_D(const QSqlResult);
508 return d->forwardOnly;
509}
510
536{
537 Q_D(QSqlResult);
538 d->forwardOnly = forward;
539}
540
551{
552 Q_D(QSqlResult);
553 if (!driver())
554 return false;
555 d->clear();
556 d->sql = query;
558 return prepare(query);
559
560 // parse the query to memorize parameter location
561 d->executedQuery = d->namedToPositionalBinding(query);
562
564 d->executedQuery = d->positionalToNamedBinding(query);
565
566 return prepare(d->executedQuery);
567}
568
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
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
621{
622 Q_D(QSqlResult);
623 bool ret;
624 // fake preparation - just replace the placeholders..
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(d->indexes.value(holder).value(0,-1));
630 QSqlField f(""_L1, val.metaType());
632 f.setValue(QVariant());
633 else
634 f.setValue(val);
635 query = query.replace(d->holders.at(i).holderPos,
636 holder.size(), driver()->formatValue(f));
637 }
638 } else {
639 qsizetype i = 0;
640 for (const QVariant &var : std::as_const(d->values)) {
641 i = query.indexOf(u'?', i);
642 if (i == -1)
643 continue;
644 QSqlField f(""_L1, var.metaType());
646 f.clear();
647 else
648 f.setValue(var);
649 const QString val = driver()->formatValue(f);
650 query = query.replace(i, 1, val);
651 i += val.size();
652 }
653 }
654
655 // have to retain the original query with placeholders
656 QString orig = lastQuery();
657 ret = reset(query);
658 d->executedQuery = query;
659 setQuery(orig);
660 d->resetBindCount();
661 return ret;
662}
663
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(index)];
675 if (!indexes.contains(index))
676 indexes.append(index);
677 if (d->values.size() <= index)
678 d->values.resize(index + 1);
679 d->values[index] = val;
680 if (paramType != QSql::In || !d->types.isEmpty())
681 d->types[index] = paramType;
682}
683
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(placeholder);
702 for (int idx : indexes) {
703 if (d->values.size() <= idx)
704 d->values.resize(idx + 1);
705 d->values[idx] = val;
706 if (paramType != QSql::In || !d->types.isEmpty())
707 d->types[idx] = paramType;
708 }
709}
710
717void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
718{
719 Q_D(QSqlResult);
720 d->binds = PositionalBinding;
721 bindValue(d->bindCount, val, paramType);
722 ++d->bindCount;
723}
724
732{
733 Q_D(const QSqlResult);
734 return d->values.value(index);
735}
736
745QVariant QSqlResult::boundValue(const QString& placeholder) const
746{
747 Q_D(const QSqlResult);
748 const QList<int> indexes = d->indexes.value(placeholder);
749 return d->values.value(indexes.value(0,-1));
750}
751
757QSql::ParamType QSqlResult::bindValueType(int index) const
758{
759 Q_D(const QSqlResult);
760 return d->types.value(index, QSql::In);
761}
762
769QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
770{
771 Q_D(const QSqlResult);
772 return d->types.value(d->indexes.value(placeholder).value(0,-1), QSql::In);
773}
774
781{
782 Q_D(const QSqlResult);
783 return d->values.size();
784}
785
793{
794 Q_D(const QSqlResult);
795 return d->values;
796}
797
807{
808 Q_D(QSqlResult);
809 return d->values;
810}
811
812
817{
818 Q_D(const QSqlResult);
819 return d->binds;
820}
821
827{
828 Q_D(QSqlResult);
829 d->clear();
830}
831
841{
842 Q_D(const QSqlResult);
843 return d->executedQuery;
844}
845
850{
851 Q_D(QSqlResult);
852 d->resetBindCount();
853}
854
861{
862 Q_D(const QSqlResult);
864 for (const QHolder &holder : std::as_const(d->holders))
865 ret.push_back(holder.holderName);
866 return ret;
867}
868
876{
877 Q_D(const QSqlResult);
878 return d->holderAt(index);
879}
880
888{
889 Q_D(const QSqlResult);
890 if (d->types.isEmpty())
891 return false;
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
909{
910 return QSqlRecord();
911}
912
928{
929 return QVariant();
930}
931
935{
936}
937
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(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(j, values.at(j).toList().at(i), QSql::In);
979 if (!exec())
980 return false;
981 }
982 return true;
983}
984
988{
989}
990
994{
995 Q_D(QSqlResult);
996 d->precisionPolicy = policy;
997}
998
1002{
1003 Q_D(const QSqlResult);
1004 return d->precisionPolicy;
1005}
1006
1010{
1011 return false;
1012}
1013
1043{
1044 return QVariant();
1045}
1046
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
constexpr bool isNull() const noexcept
Returns true if the character is the Unicode character 0x0000 ('\0'); otherwise returns false.
Definition qchar.h:463
\inmodule QtCore\reentrant
Definition qdatetime.h:257
\inmodule QtCore \reentrant
Definition qdatetime.h:27
\inmodule QtCore
Definition qhash.h:1135
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
T value(qsizetype i) const
Definition qlist.h:661
void append(parameter_type t)
Definition qlist.h:441
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:25
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:32
@ NamedPlaceholders
Definition qsqldriver.h:33
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:25
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()
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:37
@ PositionalBinding
Definition qsqlresult.h:38
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 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:108
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
\inmodule QtCore \reentrant
Definition qdatetime.h:189
\inmodule QtCore
Definition quuid.h:31
\inmodule QtCore
Definition qvariant.h:64
int typeId() const
Returns the storage type of the value stored in the variant.
Definition qvariant.h:337
bool isNull() const
Returns true if this is a null variant, false otherwise.
QMetaType metaType() const
const void * constData() const
Definition qvariant.h:446
QSet< QString >::iterator it
@ AfterLastRow
Definition qtsqlglobal.h:23
@ BeforeFirstRow
Definition qtsqlglobal.h:22
NumericalPrecisionPolicy
Definition qtsqlglobal.h:44
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
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:70
unsigned int uint
Definition qtypes.h:29
QVariant variant
[1]
QMimeDatabase db
[0]
selection select(topLeft, bottomRight)
QSizePolicy policy
QString holderName
bool contains(const AT &t) const noexcept
Definition qlist.h:44