QSqlQuery: complete the deprecation/removal of its copies

QSqlQuery has been made movable in Qt 6.2
(14f9f00fdb2dc428610c08e3d9d03e38e9602166). The pre-existing copy
operations have been deprecated, but not removed, in order to preserve
SC/BC.

This left us with two issues:

1) Whether or not to keep the deprecated copies in Qt 7. The answer is
no: the copy operations are impossible to implement in a way consistent
with value semantics (the state of the DB driver can't be copied in
general). Therefore, mark the related APIs as to-be-removed, and not
just deprecated.

2) While we no longer copy QSqlQuery from Qt code directly, QMetaType
still detects the presence of the copy constructor and extracts it,
triggering the deprecation warning.

Rather than unconditionally suppressing the warning (which will hide any
similar issue we might have in the future), add a local workaround that
raises a runtime warning if QSqlQuery is copied through QMetaType, while
not raising the deprecation warning when building Qt itself.

[ChangeLog][QtSql][QSqlQuery] Copying a QSqlQuery object via QMetaType
now raises a runtime warning. Note that copy operations for QSqlQuery
objects have already been deprecated since Qt 6.2, and are planned to be
removed in Qt 7.

Fixes: QTBUG-132752
Task-number: QTBUG-91766
Change-Id: I48714ad53ec706a5e4e055c45a1c05f372382940
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit f744cef06cf3a56591782f487c545b55b2a673fb)
This commit is contained in:
Giuseppe D'Angelo 2025-01-13 14:17:29 +01:00
parent 4e475b5cc2
commit 97880102dc
7 changed files with 69 additions and 9 deletions

View File

@ -39,6 +39,7 @@
# include "qcborarray.h"
# include "qcbormap.h"
# include "qbytearraylist.h"
# include "qloggingcategory.h"
# include "qmetaobject.h"
# include "qsequentialiterable.h"
# include "qassociativeiterable.h"
@ -61,6 +62,10 @@
QT_BEGIN_NAMESPACE
#ifndef QT_BOOTSTRAPPED
Q_STATIC_LOGGING_CATEGORY(lcMetatypeDeprecated, "qt.core.qmetatype.deprecated");
#endif
#define NS(x) QT_PREPEND_NAMESPACE(x)
QT_IMPL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl, QPairVariantInterfaceImpl)
@ -3280,6 +3285,13 @@ QMetaType::QMetaType(int typeId) : QMetaType(interfaceForType(typeId)) {}
*/
namespace QtPrivate {
#if !defined(QT_BOOTSTRAPPED)
void QMetaTypeCopyTraits::warnAboutDeprecatedCopy(const char *name)
{
qCWarning(lcMetatypeDeprecated, "QMetaType: copy construction of type '%s' is deprecated", name);
}
#endif
#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
// Explicit instantiation definition

View File

@ -28,7 +28,7 @@
#include <map>
#include <functional>
#include <optional>
#include <QtCore/q20type_traits.h>
#include <QtCore/qxptype_traits.h>
#ifdef Bool
#error qmetatype.h must be included before any header file that defines Bool
@ -2400,6 +2400,20 @@ struct QDataStreamOperatorForType <T, true>
# pragma GCC visibility push(hidden)
#endif
// ### Qt 7: consider removing this infrastructure if nothing uses it
// (see also getCopyCtr())
namespace QMetaTypeCopyTraits
{
// Hack to suppress deprecation warnings from types
// with deprecated copy operations, cf. QTBUG-132752
template <typename T>
using HasDeprecatedCopyConstructorTest = typename T::_q_hasDeprecatedCopyConstructor;
#if !defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT void warnAboutDeprecatedCopy(const char *name);
#endif
} // namespace QMetaTypeCopyTraits
template<typename S>
class QMetaTypeForType
{
@ -2457,7 +2471,14 @@ public:
{
if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) {
return [](const QMetaTypeInterface *, void *addr, const void *other) {
new (addr) S(*reinterpret_cast<const S *>(other));
if constexpr (qxp::is_detected_v<QMetaTypeCopyTraits::HasDeprecatedCopyConstructorTest, S>) {
#if !defined(QT_BOOTSTRAPPED)
QMetaTypeCopyTraits::warnAboutDeprecatedCopy(getName());
#endif
QT_IGNORE_DEPRECATIONS(new (addr) S(*reinterpret_cast<const S *>(other));)
} else {
new (addr) S(*reinterpret_cast<const S *>(other));
}
};
} else {
return nullptr;

View File

@ -216,11 +216,12 @@ QSqlQuery::~QSqlQuery()
delete d;
}
#if QT_DEPRECATED_SINCE(6, 2)
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
/*!
Constructs a copy of \a other.
\deprecated QSqlQuery cannot be meaningfully copied. Prepared
\deprecated [6.2] QSqlQuery cannot be meaningfully copied, and
therefore will no longer be copiable in Qt 7. Prepared
statements, bound values and so on will not work correctly, depending
on your database driver (for instance, changing the copy will affect
the original). Treat QSqlQuery as a move-only type instead.
@ -235,7 +236,8 @@ QSqlQuery::QSqlQuery(const QSqlQuery& other)
/*!
Assigns \a other to this object.
\deprecated QSqlQuery cannot be meaningfully copied. Prepared
\deprecated [6.2] QSqlQuery cannot be meaningfully copied, and
therefore will no longer be copiable in Qt 7. Prepared
statements, bound values and so on will not work correctly, depending
on your database driver (for instance, changing the copy will affect
the original). Treat QSqlQuery as a move-only type instead.

View File

@ -32,7 +32,7 @@ public:
explicit QSqlQuery(const QString& query = QString(), const QSqlDatabase &db = QSqlDatabase());
explicit QSqlQuery(const QSqlDatabase &db);
#if QT_DEPRECATED_SINCE(6, 2)
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
QT_DEPRECATED_VERSION_X_6_2("QSqlQuery is not meant to be copied. Use move construction instead.")
QSqlQuery(const QSqlQuery &other);
QT_DEPRECATED_VERSION_X_6_2("QSqlQuery is not meant to be copied. Use move assignment instead.")
@ -111,6 +111,10 @@ public:
void finish();
bool nextResult();
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
// Avoid raising warnings in QMetaType, cf. QTBUG-132752
using _q_hasDeprecatedCopyConstructor = void;
#endif
private:
QSqlQueryPrivate* d;
};

View File

@ -379,9 +379,11 @@ void QSqlQueryModel::queryChange()
// do nothing
}
#if QT_DEPRECATED_SINCE(6, 2)
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
/*!
\deprecated [6.2] Use the \c{setQuery(QSqlQuery &&query)} overload instead.
This overload will be removed in Qt 7.
\overload
*/
void QSqlQueryModel::setQuery(const QSqlQuery &query)
@ -389,7 +391,7 @@ void QSqlQueryModel::setQuery(const QSqlQuery &query)
QT_IGNORE_DEPRECATIONS(QSqlQuery copy = query;)
setQuery(std::move(copy));
}
#endif // QT_DEPRECATED_SINCE(6, 2)
#endif // QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
/*!
Resets the model and sets the data provider to be the given \a

View File

@ -40,7 +40,7 @@ public:
bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;
bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override;
#if QT_DEPRECATED_SINCE(6, 2)
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
QT_DEPRECATED_VERSION_X_6_2("QSqlQuery is not meant to be copied. Pass it by move instead.")
void setQuery(const QSqlQuery &query);
#endif

View File

@ -270,6 +270,13 @@ private slots:
// invalidQuery() if run later; so put this one last !
void prematureExec_data() { generic_data(); }
void prematureExec();
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
// cleanup() is data-driven
void qmetatypeDeprecatedCopy_data() { generic_data(); }
void qmetatypeDeprecatedCopy();
#endif
private:
// returns all database connections
void generic_data(const QString &engine=QString());
@ -5239,5 +5246,17 @@ void tst_QSqlQuery::psqlJsonOperator()
}
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 2)
void tst_QSqlQuery::qmetatypeDeprecatedCopy()
{
QMetaType mt = QMetaType::fromType<QSqlQuery>();
QSqlQuery query;
QTest::ignoreMessage(QtWarningMsg, "QMetaType: copy construction of type 'QSqlQuery' is deprecated");
void *copy = mt.create(&query);
mt.destroy(copy);
}
#endif
QTEST_MAIN(tst_QSqlQuery)
#include "tst_qsqlquery.moc"