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
qsqlquery.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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 "qsqlquery.h"
5
6//#define QT_DEBUG_SQL
7
8#include "qatomic.h"
9#include "qdebug.h"
10#include "qloggingcategory.h"
11#include "qsqlrecord.h"
12#include "qsqlresult.h"
13#include "qsqldriver.h"
14#include "qsqldatabase.h"
15#include "private/qsqlnulldriver_p.h"
16
17#ifdef QT_DEBUG_SQL
18#include "qelapsedtimer.h"
19#endif
20
22
23Q_STATIC_LOGGING_CATEGORY(lcSqlQuery, "qt.sql.qsqlquery")
24
35
36Q_GLOBAL_STATIC_WITH_ARGS(QSqlQueryPrivate, nullQueryPrivate, (nullptr))
38Q_GLOBAL_STATIC_WITH_ARGS(QSqlNullResult, nullResult, (nullDriver()))
39
41{
42 QSqlQueryPrivate *null = nullQueryPrivate();
43 null->ref.ref();
44 return null;
45}
46
51 : ref(1), sqlResult(result)
52{
53 if (!sqlResult)
54 sqlResult = nullResult();
55}
56
58{
59 QSqlResult *nr = nullResult();
60 if (!nr || sqlResult == nr)
61 return;
62 delete sqlResult;
63}
64
208
214{
215 if (d && !d->ref.deref())
216 delete d;
217}
218
219#if QT_DEPRECATED_SINCE(6, 2)
230{
231 d = other.d;
232 d->ref.ref();
233}
234
245{
246 qAtomicAssign(d, other.d);
247 return *this;
248}
249#endif
250
273static void qInit(QSqlQuery *q, const QString& query, const QSqlDatabase &db)
274{
275 QSqlDatabase database = db;
276 if (!database.isValid()) {
277 database =
279 }
280 if (database.isValid())
281 *q = QSqlQuery(database.driver()->createResult());
282
283 if (!query.isEmpty())
284 q->exec(query);
285}
286
300
313
324bool QSqlQuery::isNull(int field) const
325{
326 return !d->sqlResult->isActive()
327 || !d->sqlResult->isValid()
328 || d->sqlResult->isNull(field);
329}
330
343{
344 qsizetype index = d->sqlResult->record().indexOf(name);
345 if (index > -1)
346 return isNull(index);
347 qCWarning(lcSqlQuery, "QSqlQuery::isNull: unknown field name '%ls'", qUtf16Printable(name.toString()));
348 return true;
349}
350
377{
378#ifdef QT_DEBUG_SQL
380 t.start();
381#endif
382 if (!driver()) {
383 qCWarning(lcSqlQuery, "QSqlQuery::exec: called before driver has been set up");
384 return false;
385 }
386 if (d->ref.loadRelaxed() != 1) {
387 bool fo = isForwardOnly();
388 *this = QSqlQuery(driver()->createResult());
390 setForwardOnly(fo);
391 } else {
392 d->sqlResult->clear();
393 d->sqlResult->setActive(false);
397 }
398 d->sqlResult->setQuery(query.trimmed());
399 if (!driver()->isOpen() || driver()->isOpenError()) {
400 qCWarning(lcSqlQuery, "QSqlQuery::exec: database not open");
401 return false;
402 }
403 if (query.isEmpty()) {
404 qCWarning(lcSqlQuery, "QSqlQuery::exec: empty query");
405 return false;
406 }
407
408 bool retval = d->sqlResult->reset(query);
409#ifdef QT_DEBUG_SQL
410 qCDebug(lcSqlQuery()).nospace() << "Executed query (" << t.elapsed() << "ms, "
411 << d->sqlResult->size()
412 << " results, " << d->sqlResult->numRowsAffected()
413 << " affected): " << d->sqlResult->lastQuery();
414#endif
415 return retval;
416}
417
438{
439 if (isActive() && isValid() && (index > -1))
440 return d->sqlResult->data(index);
441 qCWarning(lcSqlQuery, "QSqlQuery::value: not positioned on a valid record");
442 return QVariant();
443}
444
457{
458 qsizetype index = d->sqlResult->record().indexOf(name);
459 if (index > -1)
460 return value(index);
461 qCWarning(lcSqlQuery, "QSqlQuery::value: unknown field name '%ls'", qUtf16Printable(name.toString()));
462 return QVariant();
463}
464
474int QSqlQuery::at() const
475{
476 return d->sqlResult->at();
477}
478
487{
488 return d->sqlResult->lastQuery();
489}
490
496{
497 return d->sqlResult->driver();
498}
499
505{
506 return d->sqlResult;
507}
508
568bool QSqlQuery::seek(int index, bool relative)
569{
570 if (!isSelect() || !isActive())
571 return false;
572 int actualIdx;
573 if (!relative) { // arbitrary seek
574 if (index < 0) {
576 return false;
577 }
578 actualIdx = index;
579 } else {
580 switch (at()) { // relative seek
582 if (index > 0)
583 actualIdx = index - 1;
584 else {
585 return false;
586 }
587 break;
589 if (index < 0) {
590 d->sqlResult->fetchLast();
591 actualIdx = at() + index + 1;
592 } else {
593 return false;
594 }
595 break;
596 default:
597 if ((at() + index) < 0) {
599 return false;
600 }
601 actualIdx = at() + index;
602 break;
603 }
604 }
605 // let drivers optimize
606 if (isForwardOnly() && actualIdx < at()) {
607 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
608 return false;
609 }
610 if (actualIdx == (at() + 1) && at() != QSql::BeforeFirstRow) {
611 if (!d->sqlResult->fetchNext()) {
613 return false;
614 }
615 return true;
616 }
617 if (actualIdx == (at() - 1)) {
618 if (!d->sqlResult->fetchPrevious()) {
620 return false;
621 }
622 return true;
623 }
624 if (!d->sqlResult->fetch(actualIdx)) {
626 return false;
627 }
628 return true;
629}
630
661{
662 if (!isSelect() || !isActive())
663 return false;
664
665 switch (at()) {
667 return d->sqlResult->fetchFirst();
669 return false;
670 default:
671 if (!d->sqlResult->fetchNext()) {
673 return false;
674 }
675 return true;
676 }
677}
678
709{
710 if (!isSelect() || !isActive())
711 return false;
712 if (isForwardOnly()) {
713 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
714 return false;
715 }
716
717 switch (at()) {
719 return false;
721 return d->sqlResult->fetchLast();
722 default:
723 if (!d->sqlResult->fetchPrevious()) {
725 return false;
726 }
727 return true;
728 }
729}
730
742{
743 if (!isSelect() || !isActive())
744 return false;
746 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
747 return false;
748 }
749 return d->sqlResult->fetchFirst();
750}
751
765{
766 if (!isSelect() || !isActive())
767 return false;
768 return d->sqlResult->fetchLast();
769}
770
784{
786 return d->sqlResult->size();
787 return -1;
788}
789
800{
801 if (isActive())
802 return d->sqlResult->numRowsAffected();
803 return -1;
804}
805
814{
815 return d->sqlResult->lastError();
816}
817
824{
825 return d->sqlResult->isValid();
826}
827
846{
847 return d->sqlResult->isActive();
848}
849
856{
857 return d->sqlResult->isSelect();
858}
859
866{
867 return d->sqlResult->isForwardOnly();
868}
869
910{
911 d->sqlResult->setForwardOnly(forward);
912}
913
933{
934 QSqlRecord rec = d->sqlResult->record();
935
936 if (isValid()) {
937 for (qsizetype i = 0; i < rec.count(); ++i)
938 rec.setValue(i, value(i));
939 }
940 return rec;
941}
942
949{
950 *this = QSqlQuery(driver()->createResult());
951}
952
980{
981 if (d->ref.loadRelaxed() != 1) {
982 bool fo = isForwardOnly();
983 *this = QSqlQuery(driver()->createResult());
984 setForwardOnly(fo);
986 } else {
987 d->sqlResult->setActive(false);
991 }
992 if (!driver()) {
993 qCWarning(lcSqlQuery, "QSqlQuery::prepare: no driver");
994 return false;
995 }
996 if (!driver()->isOpen() || driver()->isOpenError()) {
997 qCWarning(lcSqlQuery, "QSqlQuery::prepare: database not open");
998 return false;
999 }
1000 if (query.isEmpty()) {
1001 qCWarning(lcSqlQuery, "QSqlQuery::prepare: empty query");
1002 return false;
1003 }
1004#ifdef QT_DEBUG_SQL
1005 qCDebug(lcSqlQuery, "\n QSqlQuery::prepare: %ls", qUtf16Printable(query));
1006#endif
1007 return d->sqlResult->savePrepare(query);
1008}
1009
1020{
1021#ifdef QT_DEBUG_SQL
1023 t.start();
1024#endif
1026
1027 if (d->sqlResult->lastError().isValid())
1029
1030 bool retval = d->sqlResult->exec();
1031#ifdef QT_DEBUG_SQL
1032 qCDebug(lcSqlQuery).nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
1033 << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
1034 << " affected): " << d->sqlResult->lastQuery();
1035#endif
1036 return retval;
1037}
1038
1091
1106void QSqlQuery::bindValue(const QString& placeholder, const QVariant& val,
1107 QSql::ParamType paramType
1108)
1109{
1110 d->sqlResult->bindValue(placeholder, val, paramType);
1111}
1112
1119void QSqlQuery::bindValue(int pos, const QVariant& val, QSql::ParamType paramType)
1120{
1121 d->sqlResult->bindValue(pos, val, paramType);
1122}
1123
1136void QSqlQuery::addBindValue(const QVariant& val, QSql::ParamType paramType)
1137{
1138 d->sqlResult->addBindValue(val, paramType);
1139}
1140
1146QVariant QSqlQuery::boundValue(const QString& placeholder) const
1147{
1148 return d->sqlResult->boundValue(placeholder);
1149}
1150
1156{
1157 return d->sqlResult->boundValue(pos);
1158}
1159
1176{
1178 return values;
1179}
1180
1195
1207{
1208 return d->sqlResult->boundValueName(pos);
1209}
1210
1224{
1225 return d->sqlResult->executedQuery();
1226}
1227
1244{
1245 return d->sqlResult->lastInsertId();
1246}
1247
1279
1287
1311
1321
1322
1335{
1336 if (isActive()) {
1340 d->sqlResult->setActive(false);
1341 }
1342}
1343
1374{
1375 if (isActive())
1376 return d->sqlResult->nextResult();
1377 return false;
1378}
1379
1381
1382#include "moc_qsqlquery.cpp"
bool isActive
\inmodule QtCore
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
\inmodule QtCore
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
The QSqlDatabase class handles a connection to a database.
bool isValid() const
Returns true if the QSqlDatabase has a valid driver.
QSqlDriver * driver() const
Returns the database driver used to access the database connection.
static const char * defaultConnection
static QSqlDatabase database(const QString &connectionName=QLatin1StringView(defaultConnection), bool open=true)
\threadsafe
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition qsqldriver.h:26
virtual QSqlResult * createResult() const =0
Creates an empty SQL result on the database.
virtual bool hasFeature(DriverFeature f) const =0
Returns true if the driver supports feature feature; otherwise returns false.
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
bool isValid() const
Returns true if an error is set, otherwise false.
QSqlQueryPrivate(QSqlResult *result)
Definition qsqlquery.cpp:50
QAtomicInt ref
Definition qsqlquery.cpp:30
QSqlResult * sqlResult
Definition qsqlquery.cpp:31
static QSqlQueryPrivate * shared_null()
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition qsqlquery.h:24
QSqlQuery & operator=(const QSqlQuery &other)=delete
bool next()
Retrieves the next record in the result, if available, and positions the query on the retrieved recor...
bool last()
Retrieves the last record in the result, if available, and positions the query on the retrieved recor...
const QSqlDriver * driver() const
Returns the database driver associated with the query.
bool previous()
Retrieves the previous record in the result, if available, and positions the query on the retrieved r...
QStringList boundValueNames() const
void finish()
Instruct the database driver that no more data will be fetched from this query until it is re-execute...
bool prepare(const QString &query)
Prepares the SQL query query for execution.
QVariant value(int i) const
Returns the value of field index in the current record.
int size() const
Returns the size of the result (number of rows returned), or -1 if the size cannot be determined or i...
int numRowsAffected() const
Returns the number of rows affected by the result's SQL statement, or -1 if it cannot be determined.
const QSqlResult * result() const
Returns the result associated with the query.
bool nextResult()
Discards the current result set and navigates to the next if available.
bool first()
Retrieves the first record in the result, if available, and positions the query on the retrieved reco...
QVariant boundValue(const QString &placeholder) const
Returns the value for the placeholder.
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
Sets \l numericalPrecisionPolicy to precisionPolicy.
bool isForwardOnly() const
Returns \l forwardOnly.
QString boundValueName(int pos) const
void clear()
Clears the result set and releases any resources held by the query.
QSqlError lastError() const
Returns error information about the last error (if any) that occurred with this query.
BatchExecutionMode
\value ValuesAsRows - Updates multiple rows.
Definition qsqlquery.h:97
@ ValuesAsColumns
Definition qsqlquery.h:97
QSqlRecord record() const
Returns a QSqlRecord containing the field information for the current query.
QString lastQuery() const
Returns the text of the current query being used, or an empty string if there is no current query tex...
bool isActive() const
Returns true if the query is {active}.
QVariant lastInsertId() const
Returns the object ID of the most recent inserted row if the database supports it.
void setForwardOnly(bool forward)
Sets \l forwardOnly to forward.
bool isPositionalBindingEnabled() const
Returns \l positionalBindingEnabled.
int at() const
Returns the current internal position of the query.
void setPositionalBindingEnabled(bool enable)
Sets \l positionalBindingEnabled to enable.
bool exec()
Executes a previously prepared SQL query.
void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType type=QSql::In)
Set the placeholder placeholder to be bound to value val in the prepared statement.
QVariantList boundValues() const
bool isSelect() const
Returns true if the current query is a SELECT statement; otherwise returns false.
QSqlQuery(QSqlResult *r)
Constructs a QSqlQuery object which uses the QSqlResult result to communicate with a database.
void addBindValue(const QVariant &val, QSql::ParamType type=QSql::In)
Adds the value val to the list of values when using positional value binding.
bool isNull(int field) const
Returns true if the query is not \l{isActive()}{active}, the query is not positioned on a valid recor...
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy
Definition qsqlquery.h:28
~QSqlQuery()
Destroys the object and frees any allocated resources.
bool isValid() const
Returns true if the query is currently positioned on a valid record; otherwise returns false.
bool execBatch(BatchExecutionMode mode=ValuesAsRows)
Executes a previously prepared SQL query in a batch.
bool seek(int i, bool relative=false)
Retrieves the record at position index, if available, and positions the query on the retrieved record...
QString executedQuery() const
Returns the last query that was successfully executed.
The QSqlRecord class encapsulates a database record.
Definition qsqlrecord.h:20
int count() const
Returns the number of fields in the record.
void setValue(int i, const QVariant &val)
Sets the value of the field at position index to val.
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.
virtual bool isNull(int i)=0
Returns true if the field at position index in the current row is null; otherwise returns false.
QString executedQuery() const
Returns the query that was actually executed.
void clear()
Clears the entire result set and releases any associated resources.
virtual bool execBatch(bool arrayBind=false)
virtual QVariant data(int i)=0
Returns the data for field index in the current row as a QVariant.
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.
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 ...
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 bool fetchLast()=0
Positions the result to the last record (last row) in the result.
QString lastQuery() const
Returns the current SQL query text, or an empty string if there isn't one.
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 bool fetchNext()
Positions the result to the next available record (row) in the result.
void resetBindCount()
Resets the number of bind parameters.
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 int size()=0
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
virtual bool fetchFirst()=0
Positions the result to the first record (row 0) in the result.
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
virtual int numRowsAffected()=0
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
virtual QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
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.
virtual bool reset(const QString &sqlquery)=0
Sets the result to use the SQL statement query for subsequent data retrieval.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qvariant.h:65
@ AfterLastRow
Definition qtsqlglobal.h:22
@ BeforeFirstRow
Definition qtsqlglobal.h:21
NumericalPrecisionPolicy
Definition qtsqlglobal.h:43
Combined button and popup list for selecting options.
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition qatomic.h:180
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
GLenum GLsizei GLsizei GLint * values
[15]
GLenum mode
GLuint index
[2]
GLboolean enable
GLint ref
GLuint name
GLenum query
GLuint GLfloat * val
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
static void qInit(QSqlQuery *q, const QString &query, const QSqlDatabase &db)
#define qUtf16Printable(string)
Definition qstring.h:1543
ptrdiff_t qsizetype
Definition qtypes.h:165
QMimeDatabase db
[0]
QSharedPointer< T > other(t)
[5]