From bc7fafd4ad331b5afd46775ffcf7ae172dc41bb1 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 4 Mar 2025 11:57:17 -0800 Subject: [PATCH] Bug 799528 - Crash on account deletion (edit) New function xaccAccountDeleteAllTransactions. Delete all transactions before deleting the account; simply deleting the splits during account destruction isn't safe. In the particular case of an imbalance account the transaction commit after deleting a split just makes a new one. --- gnucash/gnome/gnc-plugin-page-account-tree.cpp | 11 +++++++++++ libgnucash/engine/Account.cpp | 13 +++++++++++++ libgnucash/engine/Account.h | 4 ++++ 3 files changed, 28 insertions(+) diff --git a/gnucash/gnome/gnc-plugin-page-account-tree.cpp b/gnucash/gnome/gnc-plugin-page-account-tree.cpp index 1321b9b30e..515173aa36 100644 --- a/gnucash/gnome/gnc-plugin-page-account-tree.cpp +++ b/gnucash/gnome/gnc-plugin-page-account-tree.cpp @@ -1694,11 +1694,22 @@ do_delete_account (Account* account, Account* saa, Account* sta, Account* ta) (AccountCb)xaccAccountMoveAllSplits, sta); } + else + { + gnc_account_foreach_descendant (account, + [](auto acc, [[maybe_unused]] auto data) + { xaccAccountDestroyAllTransactions(acc); }, + nullptr); + } if (ta) { /* Move the splits of the account to be deleted. */ xaccAccountMoveAllSplits (account, ta); } + else + { + xaccAccountDestroyAllTransactions (account); + } xaccAccountCommitEdit (account); /* Drop all references from the state file for diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 438a0d8d04..8437e8f887 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -49,6 +49,7 @@ #include #include #include +#include static QofLogModule log_module = GNC_MOD_ACCOUNT; @@ -1596,6 +1597,18 @@ xaccAccountDestroy (Account *acc) xaccAccountCommitEdit (acc); } +void +xaccAccountDestroyAllTransactions(Account *acc) +{ + auto priv = GET_PRIVATE(acc); + std::vector transactions; + std::transform(priv->splits.begin(), priv->splits.end(), + back_inserter(transactions), + [](auto split) { return split->parent; }); + std::for_each(transactions.rbegin(), transactions.rend(), + [](auto trans) { xaccTransDestroy (trans); }); +} + /********************************************************************\ \********************************************************************/ diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h index eea91ac018..3adbd4d1b7 100644 --- a/libgnucash/engine/Account.h +++ b/libgnucash/engine/Account.h @@ -210,6 +210,10 @@ typedef enum * (by calling xaccAccountBeginEdit()) before calling this routine.*/ void xaccAccountDestroy (Account *account); + /** Destroy all of the transactions that parent splits in an account. + */ + void xaccAccountDestroyAllTransactions(Account *acc); + /** Compare two accounts for equality - this is a deep compare. */ gboolean xaccAccountEqual(const Account *a, const Account* b, gboolean check_guids);