From 0e371d71dd746fc714cb6997ba0fa55cbc3c1493 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Wed, 15 Jan 2025 13:01:40 +0100 Subject: [PATCH] Check QSqlQuery errors when doing a query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is more for me than the end user, because if there is an error with a query, there is—almost aways—nothing a user can do, since it is probably an error in the static SQL string or the database. However, it is better to show an error, than to do nothing at all when there is a failure. According to Qt’s documentation[0], QFuture relies on exceptions for the error handling. At first i assumed that i had to attach an onFailed handler to QFuture in order to receive that exception and skip the then handler. However, i can not attach the onFailure inside Database::query, before returning the QFuture, because the subsequent then is only executed when there _is_ an error, never in the normal, non-exceptional, case. I would have to add the onFailure after then. Nonetheless, i found out that there is no need for onFailure: since i do not call result(), i do not get the exception, and the actual work is performed in the then handler when no exception is raised. [0]: https://doc.qt.io/qt-6/qfuture.html --- src/database.cpp | 11 +++++++++++ src/database.h | 3 +++ src/timelinelistmodel.cpp | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/database.cpp b/src/database.cpp index 91fdd87..d8f3d65 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -89,4 +89,15 @@ QFuture Database::close() }); } +void Database::checkError(const QSqlQuery &query) +{ + QSqlError lastError = query.lastError(); + if (!lastError.isValid()) { + return; + } + QString errorMessage = lastError.text(); + emit getInstance().errorOcurred(errorMessage); + throw std::runtime_error(errorMessage.toStdString()); +} + #include "moc_database.cpp" diff --git a/src/database.h b/src/database.h index 620f3f8..8032afe 100644 --- a/src/database.h +++ b/src/database.h @@ -7,6 +7,7 @@ #include #include +class QSqlQuery; class Database : public QObject { Q_OBJECT @@ -27,6 +28,8 @@ public: const QString &connectOptions); Q_INVOKABLE QFuture close(); + static void checkError(const QSqlQuery &query); + template static auto query(Function &&f) { diff --git a/src/timelinelistmodel.cpp b/src/timelinelistmodel.cpp index 3acdff9..a142262 100644 --- a/src/timelinelistmodel.cpp +++ b/src/timelinelistmodel.cpp @@ -85,6 +85,7 @@ void TimelineListModel::fetch() Results results; { QSqlQuery query("select campsite_id, label from campsite order by label, campsite_id"); + Database::checkError(query); while (query.next()) { Lodging item{query.value(0).toInt(), query.value(1).toString()}; results.lodgings.append(item); @@ -104,6 +105,7 @@ void TimelineListModel::fetch() " join booking using (booking_id) " " order by lower(booking_campsite.stay), booking_id " ""); + Database::checkError(query); while (query.next()) { int lodgingId = query.value(0).toInt(); auto *item = new TimelineModel::Item{