commit:     f357498b80dfdda0ca517e89d9962c54d86505be
Author:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
AuthorDate: Sun Nov  9 17:33:31 2025 +0000
Commit:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
CommitDate: Sun Nov  9 18:05:49 2025 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=f357498b

kde-apps/akonadi: Fix akonadi-db-migrator

Bug: https://bugs.gentoo.org/936102
Signed-off-by: Andreas Sturmlechner <asturm <AT> gentoo.org>

 kde-apps/akonadi/akonadi-25.08.3-r1.ebuild         |  68 +++++++
 .../files/akonadi-25.08.3-fix-db-migration.patch   | 210 +++++++++++++++++++++
 2 files changed, 278 insertions(+)

diff --git a/kde-apps/akonadi/akonadi-25.08.3-r1.ebuild 
b/kde-apps/akonadi/akonadi-25.08.3-r1.ebuild
new file mode 100644
index 000000000000..a38341cbcfe7
--- /dev/null
+++ b/kde-apps/akonadi/akonadi-25.08.3-r1.ebuild
@@ -0,0 +1,68 @@
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+ECM_DESIGNERPLUGIN="true"
+ECM_QTHELP="true"
+ECM_TEST="forceoptional"
+KFMIN=6.16.0
+QTMIN=6.9.1
+VIRTUALDBUS_TEST="true"
+inherit ecm gear.kde.org xdg
+
+DESCRIPTION="Storage service for PIM data and libraries for PIM apps"
+HOMEPAGE="https://community.kde.org/KDE_PIM/akonadi";
+
+LICENSE="LGPL-2.1+"
+SLOT="6/$(ver_cut 1-2)"
+KEYWORDS="~amd64 ~arm64"
+IUSE="tools +webengine xml"
+
+REQUIRED_USE="test? ( tools )"
+
+# some akonadi tests time out, that probably needs more work as it's ~700 tests
+RESTRICT="test"
+
+COMMON_DEPEND="
+       app-arch/xz-utils
+       >=dev-qt/qtbase-${QTMIN}:6[dbus,gui,network,sql,widgets,xml]
+       >=dev-qt/qtdeclarative-${QTMIN}:6
+       >=kde-frameworks/kcolorscheme-${KFMIN}:6
+       >=kde-frameworks/kconfig-${KFMIN}:6
+       >=kde-frameworks/kconfigwidgets-${KFMIN}:6
+       >=kde-frameworks/kcoreaddons-${KFMIN}:6
+       >=kde-frameworks/kcrash-${KFMIN}:6
+       >=kde-frameworks/ki18n-${KFMIN}:6
+       >=kde-frameworks/kiconthemes-${KFMIN}:6
+       >=kde-frameworks/kitemmodels-${KFMIN}:6
+       >=kde-frameworks/kwidgetsaddons-${KFMIN}:6
+       >=kde-frameworks/kwindowsystem-${KFMIN}:6
+       >=kde-frameworks/kxmlgui-${KFMIN}:6
+       webengine? (
+               kde-apps/kaccounts-integration:6
+               >=net-libs/accounts-qt-1.17[qt6(+)]
+       )
+       xml? ( dev-libs/libxml2:= )
+"
+DEPEND="${COMMON_DEPEND}
+       dev-libs/libxslt
+       test? ( sys-apps/dbus )
+"
+RDEPEND="${COMMON_DEPEND}
+       !<app-office/merkuro-25.07.80
+       kde-apps/akonadi-config
+"
+
+PATCHES=( "${FILESDIR}/${P}-fix-db-migration.patch" ) # bug #936102, in 25.12
+
+src_configure() {
+       local mycmakeargs=(
+               -DBUILD_TOOLS=$(usex tools)
+               $(cmake_use_find_package webengine AccountsQt6)
+               $(cmake_use_find_package webengine KAccounts6)
+               $(cmake_use_find_package xml LibXml2)
+       )
+
+       ecm_src_configure
+}

diff --git a/kde-apps/akonadi/files/akonadi-25.08.3-fix-db-migration.patch 
b/kde-apps/akonadi/files/akonadi-25.08.3-fix-db-migration.patch
new file mode 100644
index 000000000000..f79f53ab6f42
--- /dev/null
+++ b/kde-apps/akonadi/files/akonadi-25.08.3-fix-db-migration.patch
@@ -0,0 +1,210 @@
+From 2e90160b6c68abe19351691a06e201c66101dcb3 Mon Sep 17 00:00:00 2001
+From: Christoph Erhardt <[email protected]>
+Date: Thu, 16 Oct 2025 18:44:07 +0200
+Subject: [PATCH 1/4] fix(storage): segfault during database migration
+
+The `akonadi-db-migrator` tool reproducibly crashes with a segmentation
+fault (or a failed assertion if built in debug mode) while executing
+`prepareDatabase()` on the destination configuration.
+
+The root cause is that both `DbInitializer` and `DbUpdater` expect
+`SchemaVersionTable` to be populated. This assumption is not met by a
+freshly created destination database: the table itself exists, but it is
+empty at this point. Consequently, `SchemaVersion::retrieveAll()`
+returns an empty list and the subsequent attempt to obtain its first
+element triggers an out-of-bounds read.
+
+Fix the issue by checking for an empty result list in both places.
+
+Refs: https://bugs.kde.org/show_bug.cgi?id=493393
+---
+ src/server/storage/dbinitializer.cpp | 17 +++++++++++------
+ src/server/storage/dbupdater.cpp     |  8 ++++++--
+ 2 files changed, 17 insertions(+), 8 deletions(-)
+
+diff --git a/src/server/storage/dbinitializer.cpp 
b/src/server/storage/dbinitializer.cpp
+index 01b3359b7..3f430ae4d 100644
+--- a/src/server/storage/dbinitializer.cpp
++++ b/src/server/storage/dbinitializer.cpp
+@@ -79,12 +79,17 @@ bool DbInitializer::run()
+ #ifndef DBINITIALIZER_UNITTEST
+         // Now finally check and set the generation identifier if necessary
+         auto store = DataStore::dataStoreForDatabase(mDatabase);
+-        SchemaVersion version = SchemaVersion::retrieveAll(store).at(0);
+-        if (version.generation() == 0) {
+-            
version.setGeneration(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
+-            version.update(store);
+-
+-            qCDebug(AKONADISERVER_LOG) << "Generation:" << 
version.generation();
++        const auto schemaVersions = SchemaVersion::retrieveAll(store);
++        if (schemaVersions.empty()) {
++            qCDebug(AKONADISERVER_LOG) << "DbInitializer: SchemaVersion not 
found; skipping generation update";
++        } else {
++            auto version = schemaVersions.at(0);
++            if (version.generation() == 0) {
++                
version.setGeneration(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
++                version.update(store);
++
++                qCDebug(AKONADISERVER_LOG) << "Generation:" << 
version.generation();
++            }
+         }
+ #endif
+ 
+diff --git a/src/server/storage/dbupdater.cpp 
b/src/server/storage/dbupdater.cpp
+index 527cb4f65..38976e0ea 100644
+--- a/src/server/storage/dbupdater.cpp
++++ b/src/server/storage/dbupdater.cpp
+@@ -42,9 +42,13 @@ DbUpdater::DbUpdater(const QSqlDatabase &database, const 
QString &filename)
+ 
+ bool DbUpdater::run()
+ {
+-    // TODO error handling
+     auto store = DataStore::dataStoreForDatabase(m_database);
+-    auto currentVersion = SchemaVersion::retrieveAll(store).at(0);
++    const auto schemaVersions = SchemaVersion::retrieveAll(store);
++    if (schemaVersions.empty()) {
++        qCDebug(AKONADISERVER_LOG) << "DbUpdater: SchemaVersion not found; 
skipping schema update";
++        return true;
++    }
++    auto currentVersion = schemaVersions.at(0);
+ 
+     UpdateSet::Map updates;
+ 
+-- 
+GitLab
+
+
+From 63eb46ac4c77ed57a7b9afee2ecddfba9a3aa3a4 Mon Sep 17 00:00:00 2001
+From: Christoph Erhardt <[email protected]>
+Date: Fri, 17 Oct 2025 23:46:59 +0200
+Subject: [PATCH 2/4] fix(dbmigrator): remove leftover entries in
+ `db_migration` directory
+
+This avoids potential issues when `db_migration` already contains a
+stale database created with an old schema version.
+---
+ src/server/dbmigrator/dbmigrator.cpp | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/server/dbmigrator/dbmigrator.cpp 
b/src/server/dbmigrator/dbmigrator.cpp
+index 575a9da16..402e55452 100644
+--- a/src/server/dbmigrator/dbmigrator.cpp
++++ b/src/server/dbmigrator/dbmigrator.cpp
+@@ -326,6 +326,19 @@ std::unique_ptr<DbConfig> dbConfigFromServerRc(const 
QString &configFile, bool o
+     }
+ 
+     const auto dbPath = overrideDbPath ? StandardDirs::saveDir("data", 
QStringLiteral("db_migration%1").arg(dbPathSuffix)) : QString{};
++
++    if (overrideDbPath) {
++        // Remove any directory entries left over from a previous run
++        try {
++            for (const auto &dirEntry : 
std::filesystem::directory_iterator(dbPath.toStdString())) {
++                std::filesystem::remove_all(dirEntry.path());
++            }
++        } catch (const std::filesystem::filesystem_error &e) {
++            qCCritical(AKONADIDBMIGRATOR_LOG) << "Error: failed to clear 
migration directory " << dbPath << ": " << e.what();
++            return {};
++        }
++    }
++
+     config->init(settings, true, dbPath);
+ 
+     return config;
+-- 
+GitLab
+
+
+From 9a730ddf1938666d98552d592de1c9867ce6dc84 Mon Sep 17 00:00:00 2001
+From: Christoph Erhardt <[email protected]>
+Date: Thu, 16 Oct 2025 18:45:14 +0200
+Subject: [PATCH 3/4] chore: remove unused `#include`s
+
+Reported by clang-tidy.
+---
+ src/server/collectionscheduler.cpp       | 1 -
+ src/server/storage/collectiontreecache.h | 2 --
+ src/server/storage/dbinitializer.cpp     | 2 --
+ 3 files changed, 5 deletions(-)
+
+diff --git a/src/server/collectionscheduler.cpp 
b/src/server/collectionscheduler.cpp
+index 41ca84ece..82098600d 100644
+--- a/src/server/collectionscheduler.cpp
++++ b/src/server/collectionscheduler.cpp
+@@ -9,7 +9,6 @@
+ #include "storage/datastore.h"
+ #include "storage/selectquerybuilder.h"
+ 
+-#include "private/tristate_p.h"
+ #include <chrono>
+ 
+ #include <QDateTime>
+diff --git a/src/server/storage/collectiontreecache.h 
b/src/server/storage/collectiontreecache.h
+index d64e73cdb..cd741e749 100644
+--- a/src/server/storage/collectiontreecache.h
++++ b/src/server/storage/collectiontreecache.h
+@@ -9,8 +9,6 @@
+ #include "akthread.h"
+ #include "entities.h"
+ 
+-#include "private/tristate_p.h"
+-
+ #include <QHash>
+ #include <QList>
+ #include <QReadWriteLock>
+diff --git a/src/server/storage/dbinitializer.cpp 
b/src/server/storage/dbinitializer.cpp
+index 3f430ae4d..3a58acf89 100644
+--- a/src/server/storage/dbinitializer.cpp
++++ b/src/server/storage/dbinitializer.cpp
+@@ -20,8 +20,6 @@
+ 
+ #include <algorithm>
+ 
+-#include "private/tristate_p.h"
+-
+ using namespace Akonadi::Server;
+ 
+ DbInitializer::Ptr DbInitializer::createInstance(const QSqlDatabase 
&database, Schema *schema)
+-- 
+GitLab
+
+
+From 19740df0fd4eaf2c5bb6e3d53a1daa32496ee01d Mon Sep 17 00:00:00 2001
+From: Christoph Erhardt <[email protected]>
+Date: Thu, 16 Oct 2025 18:46:15 +0200
+Subject: [PATCH 4/4] chore: use `QDateTime::currentSecsSinceEpoch()`
+
+Recommended by clazy.
+---
+ src/server/search/searchmanager.cpp  | 2 +-
+ src/server/storage/dbinitializer.cpp | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/server/search/searchmanager.cpp 
b/src/server/search/searchmanager.cpp
+index 7f7d7d05d..17072f28d 100644
+--- a/src/server/search/searchmanager.cpp
++++ b/src/server/search/searchmanager.cpp
+@@ -294,7 +294,7 @@ void SearchManager::updateSearchImpl(const Collection 
&collection)
+     }
+ 
+     // Query all plugins for search results
+-    const QByteArray id = "searchUpdate-" + 
QByteArray::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
++    const QByteArray id = "searchUpdate-" + 
QByteArray::number(QDateTime::currentSecsSinceEpoch());
+     SearchRequest request(id, *this, mAgentSearchManager);
+     request.setCollections(queryCollections);
+     request.setMimeTypes(queryMimeTypes);
+diff --git a/src/server/storage/dbinitializer.cpp 
b/src/server/storage/dbinitializer.cpp
+index 3a58acf89..4e8d18a07 100644
+--- a/src/server/storage/dbinitializer.cpp
++++ b/src/server/storage/dbinitializer.cpp
+@@ -83,7 +83,7 @@ bool DbInitializer::run()
+         } else {
+             auto version = schemaVersions.at(0);
+             if (version.generation() == 0) {
+-                
version.setGeneration(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
++                version.setGeneration(QDateTime::currentSecsSinceEpoch());
+                 version.update(store);
+ 
+                 qCDebug(AKONADISERVER_LOG) << "Generation:" << 
version.generation();
+-- 
+GitLab
+

Reply via email to