From cb4c6b59b914cd2a42d86691a1869c5d2750cfea Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 23 Oct 2024 16:36:43 +0200 Subject: [PATCH] historydb: Prevent insertion of duplicate group packages When a package is included in a comps group multiple times, dnf5 attempts to insert that package multiple times into the `comps_group_package table` of the transaction history database. However, the table enforces a unique constraint on the (group_id, name_id) tuple. This results in terminating dnf5 process. This patch modifies the CompsGroupPackageDbUtils::comps_group_packages_insert() method to track which packages have already been inserted and skip duplicates. Here is an example of such group with duplicated packages from rpmfusion repository (see the `libavcodec-freeworld` package): multimedia Multimedia Audio/video framework common to desktops false false gstreamer1-plugins-bad-freeworld gstreamer1-plugins-ugly libavcodec-freeworld libavcodec-freeworld libavcodec-freeworld libheif-freeworld pipewire-codec-aptx qt5-qtwebengine-freeworld vlc-plugins-freeworld Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2263762 --- libdnf5/transaction/db/comps_group_package.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libdnf5/transaction/db/comps_group_package.cpp b/libdnf5/transaction/db/comps_group_package.cpp index f39a2e8dc..d3d33d8a0 100644 --- a/libdnf5/transaction/db/comps_group_package.cpp +++ b/libdnf5/transaction/db/comps_group_package.cpp @@ -27,6 +27,7 @@ along with libdnf. If not, see . #include #include +#include namespace libdnf5::transaction { @@ -92,11 +93,16 @@ static std::unique_ptr comps_group_package_i void CompsGroupPackageDbUtils::comps_group_packages_insert(libdnf5::utils::SQLite3 & conn, CompsGroup & group) { auto query_pkg_name_insert_if_not_exists = pkg_name_insert_if_not_exists_new_query(conn); auto query = comps_group_package_insert_new_query(conn); + std::unordered_set inserted_packages; for (auto & pkg : group.get_packages()) { // insert package name into 'pkg_name' table if not exists - pkg_name_insert_if_not_exists(*query_pkg_name_insert_if_not_exists, pkg.get_name()); - query->bindv( - group.get_item_id(), pkg.get_name(), pkg.get_installed(), static_cast(pkg.get_package_type())); + auto [pkg_name, inserted] = inserted_packages.emplace(pkg.get_name()); + if (!inserted) { + // the package is duplicated in comps definition, skip it + continue; + } + pkg_name_insert_if_not_exists(*query_pkg_name_insert_if_not_exists, *pkg_name); + query->bindv(group.get_item_id(), *pkg_name, pkg.get_installed(), static_cast(pkg.get_package_type())); query->step(); pkg.set_id(query->last_insert_rowid()); query->reset();