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
23static Q_LOGGING_CATEGORY(lcSqlQuery, "qt.sql.qsqlquery")
24
25class QSqlQueryPrivate
26{
27public:
28 QSqlQueryPrivate(QSqlResult* result);
29 ~QSqlQueryPrivate();
31 QSqlResult* sqlResult;
32
33 static QSqlQueryPrivate* shared_null();
34};
35
36Q_GLOBAL_STATIC_WITH_ARGS(QSqlQueryPrivate, nullQueryPrivate, (nullptr))
38Q_GLOBAL_STATIC_WITH_ARGS(QSqlNullResult, nullResult, (nullDriver()))
39
40QSqlQueryPrivate* QSqlQueryPrivate::shared_null()
41{
42 QSqlQueryPrivate *null = nullQueryPrivate();
43 null->ref.ref();
44 return null;
45}
46
50QSqlQueryPrivate::QSqlQueryPrivate(QSqlResult* result)
51 : ref(1), sqlResult(result)
52{
53 if (!sqlResult)
54 sqlResult = nullResult();
55}
56
57QSqlQueryPrivate::~QSqlQueryPrivate()
58{
59 QSqlResult *nr = nullResult();
60 if (!nr || sqlResult == nr)
61 return;
62 delete sqlResult;
63}
64
205{
206 d = new QSqlQueryPrivate(result);
207}
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{
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
296{
297 d = QSqlQueryPrivate::shared_null();
298 qInit(this, query, db);
299}
300
309{
310 d = QSqlQueryPrivate::shared_null();
311 qInit(this, QString(), db);
312}
313
324bool QSqlQuery::isNull(int field) const
325{
326 return !d->sqlResult->isActive()
327 || !d->sqlResult->isValid()
328 || d->sqlResult->isNull(field);
329}
330
335{
336 return isNull(QStringView(name));
337}
338
348{
349 qsizetype index = d->sqlResult->record().indexOf(name);
350 if (index > -1)
351 return isNull(index);
352 qCWarning(lcSqlQuery, "QSqlQuery::isNull: unknown field name '%ls'", qUtf16Printable(name.toString()));
353 return true;
354}
355
382{
383#ifdef QT_DEBUG_SQL
385 t.start();
386#endif
387 if (!driver()) {
388 qCWarning(lcSqlQuery, "QSqlQuery::exec: called before driver has been set up");
389 return false;
390 }
391 if (d->ref.loadRelaxed() != 1) {
392 bool fo = isForwardOnly();
393 *this = QSqlQuery(driver()->createResult());
394 d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
395 setForwardOnly(fo);
396 } else {
397 d->sqlResult->clear();
398 d->sqlResult->setActive(false);
399 d->sqlResult->setLastError(QSqlError());
400 d->sqlResult->setAt(QSql::BeforeFirstRow);
401 d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
402 }
403 d->sqlResult->setQuery(query.trimmed());
404 if (!driver()->isOpen() || driver()->isOpenError()) {
405 qCWarning(lcSqlQuery, "QSqlQuery::exec: database not open");
406 return false;
407 }
408 if (query.isEmpty()) {
409 qCWarning(lcSqlQuery, "QSqlQuery::exec: empty query");
410 return false;
411 }
412
413 bool retval = d->sqlResult->reset(query);
414#ifdef QT_DEBUG_SQL
415 qCDebug(lcSqlQuery()).nospace() << "Executed query (" << t.elapsed() << "ms, "
416 << d->sqlResult->size()
417 << " results, " << d->sqlResult->numRowsAffected()
418 << " affected): " << d->sqlResult->lastQuery();
419#endif
420 return retval;
421}
422
443{
444 if (isActive() && isValid() && (index > -1))
445 return d->sqlResult->data(index);
446 qCWarning(lcSqlQuery, "QSqlQuery::value: not positioned on a valid record");
447 return QVariant();
448}
449
454{
455 return value(QStringView(name));
456}
457
467{
468 qsizetype index = d->sqlResult->record().indexOf(name);
469 if (index > -1)
470 return value(index);
471 qCWarning(lcSqlQuery, "QSqlQuery::value: unknown field name '%ls'", qUtf16Printable(name.toString()));
472 return QVariant();
473}
474
484int QSqlQuery::at() const
485{
486 return d->sqlResult->at();
487}
488
497{
498 return d->sqlResult->lastQuery();
499}
500
506{
507 return d->sqlResult->driver();
508}
509
515{
516 return d->sqlResult;
517}
518
578bool QSqlQuery::seek(int index, bool relative)
579{
580 if (!isSelect() || !isActive())
581 return false;
582 int actualIdx;
583 if (!relative) { // arbitrary seek
584 if (index < 0) {
585 d->sqlResult->setAt(QSql::BeforeFirstRow);
586 return false;
587 }
588 actualIdx = index;
589 } else {
590 switch (at()) { // relative seek
592 if (index > 0)
593 actualIdx = index - 1;
594 else {
595 return false;
596 }
597 break;
599 if (index < 0) {
600 d->sqlResult->fetchLast();
601 actualIdx = at() + index + 1;
602 } else {
603 return false;
604 }
605 break;
606 default:
607 if ((at() + index) < 0) {
608 d->sqlResult->setAt(QSql::BeforeFirstRow);
609 return false;
610 }
611 actualIdx = at() + index;
612 break;
613 }
614 }
615 // let drivers optimize
616 if (isForwardOnly() && actualIdx < at()) {
617 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
618 return false;
619 }
620 if (actualIdx == (at() + 1) && at() != QSql::BeforeFirstRow) {
621 if (!d->sqlResult->fetchNext()) {
622 d->sqlResult->setAt(QSql::AfterLastRow);
623 return false;
624 }
625 return true;
626 }
627 if (actualIdx == (at() - 1)) {
628 if (!d->sqlResult->fetchPrevious()) {
629 d->sqlResult->setAt(QSql::BeforeFirstRow);
630 return false;
631 }
632 return true;
633 }
634 if (!d->sqlResult->fetch(actualIdx)) {
635 d->sqlResult->setAt(QSql::AfterLastRow);
636 return false;
637 }
638 return true;
639}
640
671{
672 if (!isSelect() || !isActive())
673 return false;
674
675 switch (at()) {
677 return d->sqlResult->fetchFirst();
679 return false;
680 default:
681 if (!d->sqlResult->fetchNext()) {
682 d->sqlResult->setAt(QSql::AfterLastRow);
683 return false;
684 }
685 return true;
686 }
687}
688
719{
720 if (!isSelect() || !isActive())
721 return false;
722 if (isForwardOnly()) {
723 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
724 return false;
725 }
726
727 switch (at()) {
729 return false;
731 return d->sqlResult->fetchLast();
732 default:
733 if (!d->sqlResult->fetchPrevious()) {
734 d->sqlResult->setAt(QSql::BeforeFirstRow);
735 return false;
736 }
737 return true;
738 }
739}
740
752{
753 if (!isSelect() || !isActive())
754 return false;
755 if (isForwardOnly() && at() > QSql::BeforeFirstRow) {
756 qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
757 return false;
758 }
759 return d->sqlResult->fetchFirst();
760}
761
775{
776 if (!isSelect() || !isActive())
777 return false;
778 return d->sqlResult->fetchLast();
779}
780
794{
795 if (isActive() && d->sqlResult->driver()->hasFeature(QSqlDriver::QuerySize))
796 return d->sqlResult->size();
797 return -1;
798}
799
810{
811 if (isActive())
812 return d->sqlResult->numRowsAffected();
813 return -1;
814}
815
824{
825 return d->sqlResult->lastError();
826}
827
834{
835 return d->sqlResult->isValid();
836}
837
856{
857 return d->sqlResult->isActive();
858}
859
866{
867 return d->sqlResult->isSelect();
868}
869
876{
877 return d->sqlResult->isForwardOnly();
878}
879
920{
921 d->sqlResult->setForwardOnly(forward);
922}
923
943{
944 QSqlRecord rec = d->sqlResult->record();
945
946 if (isValid()) {
947 for (qsizetype i = 0; i < rec.count(); ++i)
948 rec.setValue(i, value(i));
949 }
950 return rec;
951}
952
959{
960 *this = QSqlQuery(driver()->createResult());
961}
962
990{
991 if (d->ref.loadRelaxed() != 1) {
992 bool fo = isForwardOnly();
993 *this = QSqlQuery(driver()->createResult());
994 setForwardOnly(fo);
995 d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
996 } else {
997 d->sqlResult->setActive(false);
998 d->sqlResult->setLastError(QSqlError());
999 d->sqlResult->setAt(QSql::BeforeFirstRow);
1000 d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
1001 }
1002 if (!driver()) {
1003 qCWarning(lcSqlQuery, "QSqlQuery::prepare: no driver");
1004 return false;
1005 }
1006 if (!driver()->isOpen() || driver()->isOpenError()) {
1007 qCWarning(lcSqlQuery, "QSqlQuery::prepare: database not open");
1008 return false;
1009 }
1010 if (query.isEmpty()) {
1011 qCWarning(lcSqlQuery, "QSqlQuery::prepare: empty query");
1012 return false;
1013 }
1014#ifdef QT_DEBUG_SQL
1015 qCDebug(lcSqlQuery, "\n QSqlQuery::prepare: %ls", qUtf16Printable(query));
1016#endif
1017 return d->sqlResult->savePrepare(query);
1018}
1019
1030{
1031#ifdef QT_DEBUG_SQL
1033 t.start();
1034#endif
1035 d->sqlResult->resetBindCount();
1036
1037 if (d->sqlResult->lastError().isValid())
1038 d->sqlResult->setLastError(QSqlError());
1039
1040 bool retval = d->sqlResult->exec();
1041#ifdef QT_DEBUG_SQL
1042 qCDebug(lcSqlQuery).nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
1043 << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
1044 << " affected): " << d->sqlResult->lastQuery();
1045#endif
1046 return retval;
1047}
1048
1097{
1098 d->sqlResult->resetBindCount();
1099 return d->sqlResult->execBatch(mode == ValuesAsColumns);
1100}
1101
1116void QSqlQuery::bindValue(const QString& placeholder, const QVariant& val,
1117 QSql::ParamType paramType
1118)
1119{
1120 d->sqlResult->bindValue(placeholder, val, paramType);
1121}
1122
1129void QSqlQuery::bindValue(int pos, const QVariant& val, QSql::ParamType paramType)
1130{
1131 d->sqlResult->bindValue(pos, val, paramType);
1132}
1133
1146void QSqlQuery::addBindValue(const QVariant& val, QSql::ParamType paramType)
1147{
1148 d->sqlResult->addBindValue(val, paramType);
1149}
1150
1156QVariant QSqlQuery::boundValue(const QString& placeholder) const
1157{
1158 return d->sqlResult->boundValue(placeholder);
1159}
1160
1166{
1167 return d->sqlResult->boundValue(pos);
1168}
1169
1186{
1187 const QVariantList values(d->sqlResult->boundValues());
1188 return values;
1189}
1190
1202{
1203 return d->sqlResult->boundValueNames();
1204}
1205
1217{
1218 return d->sqlResult->boundValueName(pos);
1219}
1220
1234{
1235 return d->sqlResult->executedQuery();
1236}
1237
1254{
1255 return d->sqlResult->lastInsertId();
1256}
1257
1286{
1287 d->sqlResult->setNumericalPrecisionPolicy(precisionPolicy);
1288}
1289
1294{
1295 return d->sqlResult->numericalPrecisionPolicy();
1296}
1297
1318{
1319 d->sqlResult->setPositionalBindingEnabled(enable);
1320}
1321
1328{
1329 return d->sqlResult->isPositionalBindingEnabled();
1330}
1331
1332
1345{
1346 if (isActive()) {
1347 d->sqlResult->setLastError(QSqlError());
1348 d->sqlResult->setAt(QSql::BeforeFirstRow);
1349 d->sqlResult->detachFromResultSet();
1350 d->sqlResult->setActive(false);
1351 }
1352}
1353
1384{
1385 if (isActive())
1386 return d->sqlResult->nextResult();
1387 return false;
1388}
1389
1391
1392#include "moc_qsqlquery.cpp"
bool isActive
\inmodule QtCore
Definition qatomic.h:112
\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.
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
bool isValid() const
Returns true if an error is set, otherwise false.
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:93
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:29
~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
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qvariant.h:65
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
query setForwardOnly(true)
@ 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 Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
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]
QAction * at