[gnc-sx-instance-model.c] refactor Scrub function

This scrubbing function calls xaccTransRollbackEdit which is
leaky. Instead of trying to fix xaccTransRollbackEdit which requires
superhuman skills, it's easiest to track the changes separately in a
GList, and use xaccTransBeginEdit/xaccTransCommitEdit only if
necessary.
This commit is contained in:
Christopher Lam 2022-07-27 21:38:31 +08:00
parent 7880f9b16f
commit 7c2a249511

View File

@ -88,41 +88,45 @@ static void _gnc_sx_instance_event_handler(QofInstance *ent, QofEventId event_ty
static gnc_commodity* get_transaction_currency(SxTxnCreationData *creation_data, SchedXaction *sx, Transaction *template_txn); static gnc_commodity* get_transaction_currency(SxTxnCreationData *creation_data, SchedXaction *sx, Transaction *template_txn);
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
static gboolean typedef struct
scrub_sx_split_numeric (Split* split, const char *debcred)
{ {
const gboolean is_credit = g_strcmp0 (debcred, "credit") == 0; const char *name;
const char *formula = is_credit ? gnc_numeric amount;
"sx-credit-formula" : "sx-debit-formula"; } ScrubItem;
const char *numeric = is_credit ?
"sx-credit-numeric" : "sx-debit-numeric"; static void
scrub_sx_split_numeric (Split* split, gboolean is_credit, GList **changes)
{
const char *formula = is_credit ? "sx-credit-formula" : "sx-debit-formula";
const char *numeric = is_credit ? "sx-credit-numeric" : "sx-debit-numeric";
char *formval; char *formval;
gnc_numeric *numval = NULL; gnc_numeric *numval = NULL;
GHashTable *parser_vars = g_hash_table_new (g_str_hash, g_str_equal); GHashTable *parser_vars = g_hash_table_new (g_str_hash, g_str_equal);
char *error_loc; char *error_loc;
gnc_numeric amount = gnc_numeric_zero (); gnc_numeric amount = gnc_numeric_zero ();
gboolean parse_result = FALSE; gboolean parse_result = FALSE;
gboolean num_val_changed = FALSE;
qof_instance_get (QOF_INSTANCE (split), qof_instance_get (QOF_INSTANCE (split), formula, &formval,
formula, &formval, numeric, &numval, NULL);
numeric, &numval,
NULL); parse_result = gnc_exp_parser_parse_separate_vars (formval, &amount,
parse_result =
gnc_exp_parser_parse_separate_vars (formval, &amount,
&error_loc, parser_vars); &error_loc, parser_vars);
if (!parse_result || g_hash_table_size (parser_vars) != 0) if (!parse_result || g_hash_table_size (parser_vars) != 0)
amount = gnc_numeric_zero (); amount = gnc_numeric_zero ();
g_hash_table_unref (parser_vars); g_hash_table_unref (parser_vars);
if (!numval || !gnc_numeric_eq (amount, *numval)) if (!numval || !gnc_numeric_eq (amount, *numval))
{ {
qof_instance_set (QOF_INSTANCE (split), ScrubItem *change = g_new (ScrubItem, 1);
numeric, &amount, change->name = numeric;
NULL); change->amount = amount;
num_val_changed = TRUE; *changes = g_list_prepend (*changes, change);
} }
g_free (formval); g_free (formval);
g_free (numval); g_free (numval);
return num_val_changed;
} }
/* Fixes error in pre-2.6.16 where the numeric slot wouldn't get changed if the /* Fixes error in pre-2.6.16 where the numeric slot wouldn't get changed if the
@ -133,14 +137,20 @@ gnc_sx_scrub_split_numerics (gpointer psplit, gpointer puser)
{ {
Split *split = GNC_SPLIT (psplit); Split *split = GNC_SPLIT (psplit);
Transaction *trans = xaccSplitGetParent (split); Transaction *trans = xaccSplitGetParent (split);
gboolean changed; GList *changes = NULL;
scrub_sx_split_numeric (split, TRUE, &changes);
scrub_sx_split_numeric (split, FALSE, &changes);
if (!changes)
return;
xaccTransBeginEdit (trans); xaccTransBeginEdit (trans);
changed = scrub_sx_split_numeric (split, "credit") + for (GList *n = changes; n; n = n->next)
scrub_sx_split_numeric (split, "debit"); {
if (!changed) ScrubItem *change = n->data;
xaccTransRollbackEdit (trans); qof_instance_set (QOF_INSTANCE (split), change->name, &change->amount, NULL);
else }
xaccTransCommitEdit (trans); xaccTransCommitEdit (trans);
g_list_free_full (changes, g_free);
} }
static void static void