gnucash maint: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Wed Aug 4 18:55:01 EDT 2021


Updated	 via  https://github.com/Gnucash/gnucash/commit/d099d39a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fd56512c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9062be3d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f6766d42 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ddc423a5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/621704eb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4a5b5f3b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/320df7e4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/41329396 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bf8fe112 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f15402a9 (commit)
	from  https://github.com/Gnucash/gnucash/commit/79d6154c (commit)



commit d099d39afd36b672a55956c34d105d940b6ea9af
Merge: fd56512cf bf8fe1123
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Aug 4 15:52:51 2021 -0700

    Merge Simon Arlott's 'commit-root-on-load' into maint.


commit fd56512cf77ad14520d7e27f8b63c13b9b023ec6
Merge: 9062be3d4 f15402a9a
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Aug 4 15:48:42 2021 -0700

    Merge Simon Arlott's 'load-test-xml' into maint.


commit 9062be3d47d669bbacf2ac4475b5243ddf416e3f
Merge: f6766d42e 413293961
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Aug 4 14:26:27 2021 -0700

    Merge Simon Arlott's 'string-cache-fixes' into maint.


commit f6766d42ece18f11e9c6ba817325a007b50cc14c
Merge: ddc423a50 4a5b5f3bf
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Aug 4 14:19:21 2021 -0700

    Merge Simon Arlott's 'string-cache-no-refcount-empty' into maint.


commit ddc423a5054f535ee56bae11a54dbb8c9a38c11b
Merge: 79d6154cb 621704ebe
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Aug 4 14:18:16 2021 -0700

    Merge Simon Arlott's 'bug-798238' into maint.


commit 621704ebeb2d182be6784ea6602c6fbd3f3b67ce
Author: Simon Arlott <sa.me.uk>
Date:   Mon Jul 12 19:23:56 2021 +0100

    Bug 798238 - "New security" dialog doesn't save the "Display symbol"
    
    When creating a new commodity the display symbol isn't saved so it defaults
    to one of the other values as appropriate.
    
    After creating the new commodity (without providing a user symbol), set
    the user symbol.

diff --git a/gnucash/gnome-utils/dialog-commodity.c b/gnucash/gnome-utils/dialog-commodity.c
index b1a50e6a5..7e9f8a86b 100644
--- a/gnucash/gnome-utils/dialog-commodity.c
+++ b/gnucash/gnome-utils/dialog-commodity.c
@@ -1301,6 +1301,8 @@ gnc_ui_commodity_dialog_to_object(CommodityWindow * w)
             c = gnc_commodity_new(book, fullname, name_space, mnemonic, code, fraction);
             w->edit_commodity = c;
             gnc_commodity_begin_edit(c);
+
+            gnc_commodity_set_user_symbol(c, user_symbol);
         }
         else
         {

commit 4a5b5f3bf2e7616c2da600ecf25bb470e5710c0c
Author: Simon Arlott <sa.me.uk>
Date:   Thu Jul 8 20:43:02 2021 +0100

    Don't cache the empty string
    
    Avoid unnecessary reference counting for uses of the empty string.

diff --git a/libgnucash/engine/qof-string-cache.cpp b/libgnucash/engine/qof-string-cache.cpp
index 68e4fe479..eb236ebd0 100644
--- a/libgnucash/engine/qof-string-cache.cpp
+++ b/libgnucash/engine/qof-string-cache.cpp
@@ -84,7 +84,7 @@ qof_string_cache_destroy (void)
 void
 qof_string_cache_remove(const char * key)
 {
-    if (key)
+    if (key && key[0] != 0)
     {
         GHashTable* cache = qof_get_string_cache();
         gpointer value;
@@ -111,6 +111,11 @@ qof_string_cache_insert(const char * key)
 {
     if (key)
     {
+        if (key[0] == 0)
+        {
+            return "";
+        }
+
         GHashTable* cache = qof_get_string_cache();
         gpointer value;
         gpointer cache_key;

commit 320df7e4096e504ca002b794064aace27007d06d
Author: Simon Arlott <sa.me.uk>
Date:   Thu Jul 8 20:42:03 2021 +0100

    Use const return values for string cache
    
    This is a prerequisite for being able to return "" (which is const) and
    none of the returned values should ever be modified.

diff --git a/gnucash/gnome-utils/gnc-component-manager.c b/gnucash/gnome-utils/gnc-component-manager.c
index 2d909dc37..b98bcc878 100644
--- a/gnucash/gnome-utils/gnc-component-manager.c
+++ b/gnucash/gnome-utils/gnc-component-manager.c
@@ -241,9 +241,9 @@ add_event_type (ComponentEventInfo *cei, QofIdTypeConst entity_type,
     mask = g_hash_table_lookup (cei->event_masks, entity_type);
     if (!mask)
     {
-        char * key = qof_string_cache_insert ((gpointer) entity_type);
+        const char * key = qof_string_cache_insert ((gpointer) entity_type);
         mask = g_new0 (QofEventId, 1);
-        g_hash_table_insert (cei->event_masks, key, mask);
+        g_hash_table_insert (cei->event_masks, (gpointer)key, mask);
     }
 
     if (or_in)
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 154ff1936..8f12f0c64 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -317,9 +317,9 @@ gnc_account_init(Account* acc)
     priv->parent   = NULL;
     priv->children = NULL;
 
-    priv->accountName = static_cast<char*>(qof_string_cache_insert(""));
-    priv->accountCode = static_cast<char*>(qof_string_cache_insert(""));
-    priv->description = static_cast<char*>(qof_string_cache_insert(""));
+    priv->accountName = qof_string_cache_insert("");
+    priv->accountCode = qof_string_cache_insert("");
+    priv->description = qof_string_cache_insert("");
 
     priv->type = ACCT_TYPE_NONE;
 
@@ -1265,9 +1265,9 @@ xaccCloneAccount(const Account *from, QofBook *book)
      * Also let caller issue the generate_event (EVENT_CREATE) */
     priv->type = from_priv->type;
 
-    priv->accountName = static_cast<char*>(qof_string_cache_insert(from_priv->accountName));
-    priv->accountCode = static_cast<char*>(qof_string_cache_insert(from_priv->accountCode));
-    priv->description = static_cast<char*>(qof_string_cache_insert(from_priv->description));
+    priv->accountName = qof_string_cache_replace(priv->accountName, from_priv->accountName);
+    priv->accountCode = qof_string_cache_replace(priv->accountCode, from_priv->accountCode);
+    priv->description = qof_string_cache_replace(priv->description, from_priv->description);
 
     qof_instance_copy_kvp (QOF_INSTANCE (ret), QOF_INSTANCE (from));
 
@@ -2327,7 +2327,7 @@ int
 xaccAccountOrder (const Account *aa, const Account *ab)
 {
     AccountPrivate *priv_aa, *priv_ab;
-    char *da, *db;
+    const char *da, *db;
     char *endptr = NULL;
     int ta, tb, result;
     long la, lb;
@@ -3264,7 +3264,7 @@ gnc_account_get_full_name(const Account *account)
     AccountPrivate *priv;
     const Account *a;
     char *fullname;
-    gchar **names;
+    const gchar **names;
     int level;
 
     /* So much for hardening the API. Too many callers to this function don't
@@ -3291,7 +3291,7 @@ gnc_account_get_full_name(const Account *account)
 
     /* Get all the pointers in the right order. The root node "entry"
      * becomes the terminating NULL pointer for the array of strings. */
-    names = (gchar **)g_malloc(level * sizeof(gchar *));
+    names = (const gchar **)g_malloc(level * sizeof(gchar *));
     names[--level] = NULL;
     for (a = account; level > 0; a = priv->parent)
     {
@@ -3300,7 +3300,7 @@ gnc_account_get_full_name(const Account *account)
     }
 
     /* Build the full name */
-    fullname =  g_strjoinv(account_separator, names);
+    fullname = g_strjoinv(account_separator, (gchar **)names);
     g_free(names);
 
     return fullname;
diff --git a/libgnucash/engine/AccountP.h b/libgnucash/engine/AccountP.h
index ea147aa83..746a1c504 100644
--- a/libgnucash/engine/AccountP.h
+++ b/libgnucash/engine/AccountP.h
@@ -62,7 +62,7 @@ typedef struct AccountPrivate
      * It is intended to a short, 5 to 30 character long string that
      * is displayed by the GUI as the account mnemonic.
      */
-    char *accountName;
+    const char *accountName;
 
     /* The accountCode is an arbitrary string assigned by the user.
      * It is intended to be reporting code that is a synonym for the
@@ -71,13 +71,13 @@ typedef struct AccountPrivate
      * as 100, 200 or 600 for top-level accounts, and 101, 102..  etc.
      * for detail accounts.
      */
-    char *accountCode;
+    const char *accountCode;
 
     /* The description is an arbitrary string assigned by the user.
      * It is intended to be a longer, 1-5 sentence description of what
      * this account is all about.
      */
-    char *description;
+    const char *description;
 
     /* The type field is the account type, picked from the enumerated
      * list that includes ACCT_TYPE_BANK, ACCT_TYPE_STOCK,
diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index 8fb6091fa..1c9cf710d 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -1495,7 +1495,7 @@ xaccSplitOrder (const Split *sa, const Split *sb)
 {
     int retval;
     int comp;
-    char *da, *db;
+    const char *da, *db;
     gboolean action_for_num;
 
     if (sa == sb) return 0;
diff --git a/libgnucash/engine/SplitP.h b/libgnucash/engine/SplitP.h
index 8e6f41bb6..335db9174 100644
--- a/libgnucash/engine/SplitP.h
+++ b/libgnucash/engine/SplitP.h
@@ -83,7 +83,7 @@ struct split_s
      * It is intended to hold a short (zero to forty character) string
      * that is displayed by the GUI along with this split.
      */
-    char  * memo;
+    const char  *memo;
 
     /* The action field is an arbitrary user-assigned value.
      * It is meant to be a very short (one to ten character) string that
@@ -91,10 +91,10 @@ struct split_s
      * Withdraw, Deposit, ATM, Check, etc. The idea is that this field
      * can be used to create custom reports or graphs of data.
      */
-    char  * action;            /* Buy, Sell, Div, etc.                      */
+    const char  *action;       /* Buy, Sell, Div, etc.                      */
 
-    time64 date_reconciled;  /* date split was reconciled                 */
-    char   reconciled;        /* The reconciled field                      */
+    time64 date_reconciled;    /* date split was reconciled                 */
+    char   reconciled;         /* The reconciled field                      */
 
     /* gains is a flag used to track the relationship between
      * capital-gains splits. Depending on its value, this flag indicates
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index e7c3cba0a..986eb8fc3 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -1699,7 +1699,8 @@ xaccTransCommitEdit (Transaction *trans)
     LEAVE ("(trans=%p)", trans);
 }
 
-#define SWAP(a, b) do { gpointer tmp = (a); (a) = (b); (b) = tmp; } while (0);
+#define SWAP_STR(a, b) do { const char *tmp = (a); (a) = (b); (b) = tmp; } while (0);
+#define SWAP(a, b)     do { gpointer tmp = (a); (a) = (b); (b) = tmp; } while (0);
 
 /* Ughhh. The Rollback function is terribly complex, and, what's worse,
  * it only rolls back the basics.  The TransCommit functions did a bunch
@@ -1738,8 +1739,8 @@ xaccTransRollbackEdit (Transaction *trans)
     /* copy the original values back in. */
 
     orig = trans->orig;
-    SWAP(trans->num, orig->num);
-    SWAP(trans->description, orig->description);
+    SWAP_STR(trans->num, orig->num);
+    SWAP_STR(trans->description, orig->description);
     trans->date_entered = orig->date_entered;
     trans->date_posted = orig->date_posted;
     SWAP(trans->common_currency, orig->common_currency);
@@ -1766,8 +1767,8 @@ xaccTransRollbackEdit (Transaction *trans)
             Split *so = onode->data;
 
             xaccSplitRollbackEdit(s);
-            SWAP(s->action, so->action);
-            SWAP(s->memo, so->memo);
+            SWAP_STR(s->action, so->action);
+            SWAP_STR(s->memo, so->memo);
 	    qof_instance_copy_kvp (QOF_INSTANCE (s), QOF_INSTANCE (so));
             s->reconciled = so->reconciled;
             s->amount = so->amount;
@@ -1915,7 +1916,7 @@ int
 xaccTransOrder_num_action (const Transaction *ta, const char *actna,
                             const Transaction *tb, const char *actnb)
 {
-    char *da, *db;
+    const char *da, *db;
     int retval;
     int64_t na, nb;
 
diff --git a/libgnucash/engine/TransactionP.h b/libgnucash/engine/TransactionP.h
index bbeef7cb0..c42f988c1 100644
--- a/libgnucash/engine/TransactionP.h
+++ b/libgnucash/engine/TransactionP.h
@@ -82,12 +82,12 @@ struct transaction_s
      * It is intended to store a short id number, typically the check number,
      * deposit number, invoice number or other tracking number.
      */
-    char * num;
+    const char *num;
 
     /* The description field is an arbitrary user-assigned value.
      * It is meant to be a short descriptive phrase.
      */
-    char * description;
+    const char *description;
 
     /* The common_currency field is the balancing common currency for
      * all the splits in the transaction.  Alternate, better(?) name:
diff --git a/libgnucash/engine/gnc-budget.c b/libgnucash/engine/gnc-budget.c
index 7865e0bfc..dc67c389a 100644
--- a/libgnucash/engine/gnc-budget.c
+++ b/libgnucash/engine/gnc-budget.c
@@ -61,10 +61,10 @@ typedef struct
 typedef struct GncBudgetPrivate
 {
     /* The name is an arbitrary string assigned by the user. */
-    gchar* name;
+    const gchar *name;
 
     /* The description is an arbitrary string assigned by the user. */
-    gchar* description;
+    const gchar *description;
 
     /* Recurrence (period info) for the budget */
     Recurrence recurrence;
diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c
index 23d5c7f3f..2d6998def 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@ -70,23 +70,23 @@ typedef struct gnc_commodityPrivate
 {
     gnc_commodity_namespace *name_space;
 
-    char    * fullname;
-    char    * mnemonic;
-    char    * printname;
-    char    * cusip;          /* CUSIP or other identifying code */
-    int       fraction;
-    char    * unique_name;
+    const char *fullname;
+    const char *mnemonic;
+    char       *printname;
+    const char *cusip;                /* CUSIP or other identifying code */
+    int         fraction;
+    char       *unique_name;
 
-    gboolean  quote_flag;	    /* user wants price quotes */
-    gnc_quote_source * quote_source;   /* current/old source of quotes */
-    char    * quote_tz;
+    gboolean    quote_flag;	      /* user wants price quotes */
+    gnc_quote_source *quote_source;   /* current/old source of quotes */
+    const char *quote_tz;
 
     /* the number of accounts using this commodity - this field is not
      * persisted */
-    int       usage_count;
+    int         usage_count;
 
     /* the default display_symbol, set in iso-4217-currencies at start-up */
-    const char * default_symbol;
+    const char *default_symbol;
 } gnc_commodityPrivate;
 
 #define GET_PRIVATE(o) \
@@ -104,7 +104,7 @@ struct gnc_commodity_namespace_s
 {
     QofInstance inst;
 
-    gchar      * name;
+    const gchar *name;
     gboolean     iso4217;
     GHashTable * cm_table;
     GList      * cm_list;
@@ -1997,7 +1997,7 @@ gnc_commodity_table_insert(gnc_commodity_table * table,
     PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
            nsp->cm_table, nsp->name);
     g_hash_table_insert(nsp->cm_table,
-                        CACHE_INSERT(priv->mnemonic),
+                        (gpointer)CACHE_INSERT(priv->mnemonic),
                         (gpointer)comm);
     nsp->cm_list = g_list_append(nsp->cm_list, comm);
 
diff --git a/libgnucash/engine/gnc-pricedb-p.h b/libgnucash/engine/gnc-pricedb-p.h
index 84ea6df73..49eaefc92 100644
--- a/libgnucash/engine/gnc-pricedb-p.h
+++ b/libgnucash/engine/gnc-pricedb-p.h
@@ -40,7 +40,7 @@ struct gnc_price_s
     gnc_commodity *currency;
     time64 tmspec;
     PriceSource source;
-    char *type;
+    const char *type;
     gnc_numeric value;
 
     /* 'private' object management fields */
diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c
index 3dd48eb4f..1b15a5e08 100644
--- a/libgnucash/engine/gnc-pricedb.c
+++ b/libgnucash/engine/gnc-pricedb.c
@@ -558,12 +558,8 @@ gnc_price_set_typestr(GNCPrice *p, const char* type)
     if (!p) return;
     if (g_strcmp0(p->type, type) != 0)
     {
-        gchar *tmp;
-
         gnc_price_begin_edit (p);
-        tmp = CACHE_INSERT((gpointer) type);
-        if (p->type) CACHE_REMOVE(p->type);
-        p->type = tmp;
+        CACHE_REPLACE(p->type, type);
         gnc_price_set_dirty(p);
         gnc_price_commit_edit (p);
     }
diff --git a/libgnucash/engine/gncAddress.c b/libgnucash/engine/gncAddress.c
index 2b4e5222c..6bd871e28 100644
--- a/libgnucash/engine/gncAddress.c
+++ b/libgnucash/engine/gncAddress.c
@@ -39,17 +39,17 @@ struct _gncAddress
 {
     QofInstance inst;
 
-    QofBook *	book;
+    QofBook *     book;
     QofInstance * parent;
-    gboolean	dirty;
-    char *	name;
-    char *	addr1;
-    char *	addr2;
-    char *	addr3;
-    char *	addr4;
-    char *	phone;
-    char *	fax;
-    char *	email;
+    gboolean      dirty;
+    const char *  name;
+    const char *  addr1;
+    const char *  addr2;
+    const char *  addr3;
+    const char *  addr4;
+    const char *  phone;
+    const char *  fax;
+    const char *  email;
 };
 
 struct _gncAddressClass
@@ -393,14 +393,10 @@ gncAddressFree (GncAddress *addr)
 /* Set functions */
 
 #define SET_STR(obj, member, str) { \
-	char * tmp; \
-	\
 	if (member == str) return; \
 	if (!g_strcmp0 (member, str)) return; \
 	gncAddressBeginEdit (obj); \
-	tmp = CACHE_INSERT (str); \
-	CACHE_REMOVE (member); \
-	member = tmp; \
+	CACHE_REPLACE(member, str); \
 	}
 
 void gncAddressSetName (GncAddress *addr, const char *name)
diff --git a/libgnucash/engine/gncBillTerm.c b/libgnucash/engine/gncBillTerm.c
index 93c03f6a7..fb6f2bb15 100644
--- a/libgnucash/engine/gncBillTerm.c
+++ b/libgnucash/engine/gncBillTerm.c
@@ -39,8 +39,8 @@ struct _gncBillTerm
     QofInstance     inst;
 
     /* 'visible' data fields directly manipulated by user */
-    char *          name;
-    char *          desc;
+    const char *    name;
+    const char *    desc;
     GncBillTermType type;
     gint            due_days;
     gint            disc_days;
@@ -72,13 +72,9 @@ static QofLogModule log_module = GNC_MOD_BUSINESS;
 #define _GNC_MOD_NAME        GNC_ID_BILLTERM
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncBillTermBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE(member, str); \
         }
 
 AS_STRING_DEC(GncBillTermType, ENUM_TERMS_TYPE)
diff --git a/libgnucash/engine/gncCustomer.c b/libgnucash/engine/gncCustomer.c
index 7d0c47939..ddb03aee0 100644
--- a/libgnucash/engine/gncCustomer.c
+++ b/libgnucash/engine/gncCustomer.c
@@ -53,9 +53,9 @@ struct _gncCustomer
     QofInstance     inst;
 
     /* The following fields are identical to 'vendor' */
-    char *          id;
-    char *          name;
-    char *          notes;
+    const char *    id;
+    const char *    name;
+    const char *    notes;
     GncBillTerm *   terms;
     GncAddress *    addr;
     gnc_commodity * currency;
@@ -371,13 +371,9 @@ static void gncCustomerFree (GncCustomer *cust)
 /* Set Functions */
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncCustomerBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE(member, str); \
         }
 
 void gncCustomerSetID (GncCustomer *cust, const char *id)
diff --git a/libgnucash/engine/gncEmployee.c b/libgnucash/engine/gncEmployee.c
index 7515d12e2..293b52dcb 100644
--- a/libgnucash/engine/gncEmployee.c
+++ b/libgnucash/engine/gncEmployee.c
@@ -47,15 +47,15 @@ static void empl_handle_qof_events (QofInstance *entity, QofEventId event_type,
 struct _gncEmployee
 {
     QofInstance     inst;
-    char *          id;
-    char *          username;
+    const char *    id;
+    const char *    username;
     GncAddress *    addr;
     gnc_commodity * currency;
     gboolean        active;
     gnc_numeric *   balance;
 
-    char *          language;
-    char *          acl;
+    const char *    language;
+    const char *    acl;
     gnc_numeric     workday;
     gnc_numeric     rate;
 
@@ -481,13 +481,9 @@ static void gncEmployeeFree (GncEmployee *employee)
 /* Set Functions */
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncEmployeeBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE (member, str); \
         }
 
 void gncEmployeeSetID (GncEmployee *employee, const char *id)
diff --git a/libgnucash/engine/gncEntry.c b/libgnucash/engine/gncEntry.c
index d48c65845..b96754463 100644
--- a/libgnucash/engine/gncEntry.c
+++ b/libgnucash/engine/gncEntry.c
@@ -44,9 +44,9 @@ struct _gncEntry
 
     time64	date;
     time64	date_entered;
-    char *	desc;
-    char *	action;
-    char *	notes;
+    const char *	desc;
+    const char *	action;
+    const char *	notes;
     gnc_numeric 	quantity;
 
     /* customer invoice data */
@@ -191,13 +191,9 @@ gboolean gncEntryPaymentStringToType (const char *str, GncEntryPaymentType *type
 #define _GNC_MOD_NAME GNC_ID_ENTRY
 
 #define SET_STR(obj, member, str) { \
-	char * tmp; \
-	\
 	if (!g_strcmp0 (member, str)) return; \
 	gncEntryBeginEdit (obj); \
-	tmp = CACHE_INSERT (str); \
-	CACHE_REMOVE (member); \
-	member = tmp; \
+	CACHE_REPLACE (member, str); \
 	}
 
 static inline void mark_entry (GncEntry *entry);
diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index 5d489cb13..6ab155f81 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -50,11 +50,11 @@ struct _gncInvoice
 {
     QofInstance   inst;
 
-    char          *id;
-    char          *notes;
+    const char    *id;
+    const char    *notes;
     gboolean      active;
 
-    char          *billing_id;
+    const char    *billing_id;
     char          *printname;
     GncBillTerm   *terms;
     GList         *entries;
@@ -87,13 +87,9 @@ static QofLogModule log_module = GNC_MOD_BUSINESS;
 #define GNC_INVOICE_DOCLINK "assoc_uri" // this is the old name for the document link, kept for compatibility
 
 #define SET_STR(obj, member, str) { \
-    char * tmp; \
-    \
     if (!g_strcmp0 (member, str)) return; \
     gncInvoiceBeginEdit (obj); \
-    tmp = CACHE_INSERT (str); \
-    CACHE_REMOVE (member); \
-    member = tmp; \
+    CACHE_REPLACE (member, str); \
     }
 
 static void mark_invoice (GncInvoice *invoice);
diff --git a/libgnucash/engine/gncJob.c b/libgnucash/engine/gncJob.c
index bb9635a01..46fb843d6 100644
--- a/libgnucash/engine/gncJob.c
+++ b/libgnucash/engine/gncJob.c
@@ -41,9 +41,9 @@
 struct _gncJob
 {
     QofInstance inst;
-    char *        id;
-    char *        name;
-    char *        desc;
+    const char *  id;
+    const char *  name;
+    const char *  desc;
     GncOwner      owner;
     gboolean      active;
 };
@@ -269,13 +269,9 @@ static void gncJobFree (GncJob *job)
 /* Set Functions */
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncJobBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE (member, str); \
         }
 
 void gncJobSetID (GncJob *job, const char *id)
diff --git a/libgnucash/engine/gncOrder.c b/libgnucash/engine/gncOrder.c
index fbf1b3bd9..24b3901f5 100644
--- a/libgnucash/engine/gncOrder.c
+++ b/libgnucash/engine/gncOrder.c
@@ -43,16 +43,16 @@ struct _gncOrder
 {
     QofInstance inst;
 
-    char *	id;
-    char *	notes;
-    gboolean 	active;
-
-    char *	reference;
-    char *	printname;
-    GncOwner	owner;
-    GList *	entries;
-    time64 	opened;
-    time64 	closed;
+    const char * id;
+    const char * notes;
+    gboolean     active;
+
+    const char * reference;
+    char *       printname;
+    GncOwner     owner;
+    GList *      entries;
+    time64       opened;
+    time64       closed;
 };
 
 struct _gncOrderClass
@@ -65,13 +65,9 @@ static QofLogModule log_module = GNC_MOD_BUSINESS;
 #define _GNC_MOD_NAME	GNC_ID_ORDER
 
 #define SET_STR(obj, member, str) { \
-	char * tmp; \
-	\
 	if (!g_strcmp0 (member, str)) return; \
 	gncOrderBeginEdit (obj); \
-	tmp = CACHE_INSERT (str); \
-	CACHE_REMOVE (member); \
-	member = tmp; \
+	CACHE_REPLACE (member, str); \
 	}
 
 static inline void mark_order (GncOrder *order);
diff --git a/libgnucash/engine/gncTaxTable.c b/libgnucash/engine/gncTaxTable.c
index 182bd0552..3cd689db5 100644
--- a/libgnucash/engine/gncTaxTable.c
+++ b/libgnucash/engine/gncTaxTable.c
@@ -37,7 +37,7 @@
 struct _gncTaxTable
 {
     QofInstance     inst;
-    char *          name;
+    const char *    name;
     GncTaxTableEntryList*  entries;
     time64          modtime;      /* internal date of last modtime */
 
@@ -136,13 +136,9 @@ gncTaxIncludedStringToType (const char *str, GncTaxIncluded *type)
 #define _GNC_MOD_NAME        GNC_ID_TAXTABLE
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncTaxTableBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE (member, str); \
         }
 
 static inline void
diff --git a/libgnucash/engine/gncVendor.c b/libgnucash/engine/gncVendor.c
index 709664314..67af18c61 100644
--- a/libgnucash/engine/gncVendor.c
+++ b/libgnucash/engine/gncVendor.c
@@ -52,9 +52,9 @@ struct _gncVendor
 {
     QofInstance     inst;
 
-    char *          id;
-    char *          name;
-    char *          notes;
+    const char *    id;
+    const char *    name;
+    const char *    notes;
     GncBillTerm *   terms;
     GncAddress *    addr;
     gnc_commodity * currency;
@@ -512,13 +512,9 @@ static void gncVendorFree (GncVendor *vendor)
 /* Set Functions */
 
 #define SET_STR(obj, member, str) { \
-        char * tmp; \
-        \
         if (!g_strcmp0 (member, str)) return; \
         gncVendorBeginEdit (obj); \
-        tmp = CACHE_INSERT (str); \
-        CACHE_REMOVE (member); \
-        member = tmp; \
+        CACHE_REPLACE (member, str); \
         }
 
 void gncVendorSetID (GncVendor *vendor, const char *id)
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 60a46edf2..6ab5bc5a6 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -50,7 +50,7 @@ KvpFrameImpl::KvpFrameImpl(const KvpFrameImpl & rhs) noexcept
     std::for_each(rhs.m_valuemap.begin(), rhs.m_valuemap.end(),
         [this](const map_type::value_type & a)
         {
-            auto key = static_cast<char *>(qof_string_cache_insert(a.first));
+            auto key = qof_string_cache_insert(a.first);
             auto val = new KvpValueImpl(*a.second);
             this->m_valuemap.insert({key,val});
         }
diff --git a/libgnucash/engine/qof-string-cache.cpp b/libgnucash/engine/qof-string-cache.cpp
index aa1b89702..68e4fe479 100644
--- a/libgnucash/engine/qof-string-cache.cpp
+++ b/libgnucash/engine/qof-string-cache.cpp
@@ -106,7 +106,7 @@ qof_string_cache_remove(const char * key)
 
 /* If the key exists in the cache, increment the refcount.  Otherwise,
  * add it with a refcount of 1. */
-char *
+const char *
 qof_string_cache_insert(const char * key)
 {
     if (key)
@@ -132,10 +132,10 @@ qof_string_cache_insert(const char * key)
     return NULL;
 }
 
-char *
+const char *
 qof_string_cache_replace(char const * dst, char const * src)
 {
-    char * tmp {qof_string_cache_insert (src)};
+    const char * tmp {qof_string_cache_insert (src)};
     qof_string_cache_remove (dst);
     return tmp;
 }
diff --git a/libgnucash/engine/qof-string-cache.h b/libgnucash/engine/qof-string-cache.h
index f45ff1b19..f8be51c5d 100644
--- a/libgnucash/engine/qof-string-cache.h
+++ b/libgnucash/engine/qof-string-cache.h
@@ -84,11 +84,11 @@ void qof_string_cache_remove(const char * key);
 /** You can use this function with g_hash_table_insert(), for the key
    (or value), as long as you use the destroy notifier above.
 */
-char * qof_string_cache_insert(const char * key);
+const char * qof_string_cache_insert(const char * key);
 
 /** Same as CACHE_REPLACE below, but safe to call from C++.
  */
-char * qof_string_cache_replace(const char * dst, const char * src);
+const char * qof_string_cache_replace(const char * dst, const char * src);
 
 #define CACHE_INSERT(str) qof_string_cache_insert((str))
 #define CACHE_REMOVE(str) qof_string_cache_remove((str))
@@ -101,7 +101,7 @@ char * qof_string_cache_replace(const char * dst, const char * src);
  * It avoids unnecessary ejection by doing INSERT before REMOVE.
 */
 #define CACHE_REPLACE(dst, src) do {          \
-        gpointer tmp = CACHE_INSERT((src));   \
+        const char *tmp = CACHE_INSERT((src));   \
         CACHE_REMOVE((dst));                  \
         (dst) = tmp;                          \
     } while (0)
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index c768296ea..adb1ff790 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -613,7 +613,7 @@ qof_book_get_collection (const QofBook *book, QofIdType entity_type)
         col = qof_collection_new (entity_type);
         g_hash_table_insert(
             book->hash_of_collections,
-            qof_string_cache_insert(entity_type), col);
+            (gpointer)qof_string_cache_insert(entity_type), col);
     }
     return col;
 }
diff --git a/libgnucash/engine/test/test-qof-string-cache.c b/libgnucash/engine/test/test-qof-string-cache.c
index f03c01032..f43a1081b 100644
--- a/libgnucash/engine/test/test-qof-string-cache.c
+++ b/libgnucash/engine/test/test-qof-string-cache.c
@@ -55,10 +55,10 @@ test_qof_string_cache( void )
     /* Strings added to the cache should always return the same string address
      * as long as the refcount > 0. */
     gchar str[100];
-    gchar* str1_1;
-    gchar* str1_2;
-    gchar* str1_3;
-    gchar* str1_4;
+    const gchar* str1_1;
+    const gchar* str1_2;
+    const gchar* str1_3;
+    const gchar* str1_4;
 
     strncpy(str, "str1", sizeof(str));
     str1_1 = qof_string_cache_insert(str);      /* Refcount = 1 */
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index 35f411322..b54163cd0 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -305,8 +305,8 @@ setup (Fixture *fixture, gconstpointer pData)
     auto accts = g_hash_table_new (g_str_hash, g_str_equal);
     guint ind;
 
-    auto root_str = static_cast<char*>(CACHE_INSERT("root"));
-    g_hash_table_insert (accts, root_str, root);
+    auto root_str = CACHE_INSERT("root");
+    g_hash_table_insert (accts, (gpointer)root_str, root);
     fixture->func = _utest_account_fill_functions ();
     if (parms == NULL)
     {
diff --git a/libgnucash/engine/test/utest-Split.cpp b/libgnucash/engine/test/utest-Split.cpp
index 660210b16..93637627c 100644
--- a/libgnucash/engine/test/utest-Split.cpp
+++ b/libgnucash/engine/test/utest-Split.cpp
@@ -79,8 +79,8 @@ setup (Fixture *fixture, gconstpointer pData)
     xaccSplitSetParent (fixture->split, txn);
     xaccTransCommitEdit (txn);
     gnc_lot_set_account (lot, acc);
-    fixture->split->action = static_cast<char*>(CACHE_INSERT ("foo"));
-    fixture->split->memo = static_cast<char*>(CACHE_INSERT ("bar"));
+    fixture->split->action = CACHE_INSERT ("foo");
+    fixture->split->memo = CACHE_INSERT ("bar");
     fixture->split->acc = acc;
     fixture->split->lot = lot;
     fixture->split->parent = txn;
diff --git a/libgnucash/engine/test/utest-Transaction.cpp b/libgnucash/engine/test/utest-Transaction.cpp
index 3cf10ebb8..beba27bab 100644
--- a/libgnucash/engine/test/utest-Transaction.cpp
+++ b/libgnucash/engine/test/utest-Transaction.cpp
@@ -137,16 +137,16 @@ setup (Fixture *fixture, gconstpointer pData)
     xaccAccountSetCommodity (fixture->acc2, fixture->curr);
     txn->date_posted = posted;
     txn->date_entered = entered;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (100000, 1000);
     split1->value = gnc_numeric_create (3200, 240);
     split2->amount = gnc_numeric_create (-3200, 240);
     split2->value = gnc_numeric_create (-3200, 240);
     split1->acc = fixture->acc1;
     split2->acc = fixture->acc2;
-    txn->num = static_cast<char*>(CACHE_INSERT ("123"));
-    txn->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
+    txn->num = CACHE_INSERT ("123");
+    txn->description = CACHE_INSERT ("Waldo Pepper");
     xaccTransBeginEdit (txn);
     {
         xaccTransSetCurrency (txn, fixture->curr);
@@ -722,7 +722,7 @@ test_xaccFreeTransaction (Fixture *fixture, gconstpointer pData)
     /* so the "free" doesn't, leaving the structure for us to test */
     g_object_ref (txn);
     g_object_ref (orig);
-    orig->num = static_cast<char*>(CACHE_INSERT (txn_num));
+    orig->num = CACHE_INSERT (txn_num);
     txn->orig = orig;
 
     fixture->func->xaccFreeTransaction (txn);
@@ -849,17 +849,17 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
     g_assert (xaccTransEqual (txn1, clone, TRUE, FALSE, TRUE, TRUE));
     g_assert_cmpint (check->hits, ==, 5);
 
-    txn1->num = g_strdup("321");
+    txn1->num = CACHE_INSERT("321");
     g_free (check->msg);
     check->msg = g_strdup ("[xaccTransEqual] num differs: 321 vs 123");
     g_assert (!xaccTransEqual (txn1, txn0, TRUE, FALSE, TRUE, TRUE));
     g_assert_cmpint (check->hits, ==, 6);
 
-    g_free(clone->num);
-    clone->num = static_cast<char*>(CACHE_INSERT("123"));
-    g_free(txn1->num);
+    g_free ((char*)clone->num);
+    clone->num = CACHE_INSERT("123");
+    CACHE_REMOVE(txn1->num);
     txn1->num = g_strdup("123");
-    clone->description = g_strdup("salt pork");
+    clone->description = CACHE_INSERT("salt pork");
     g_free (check->msg);
     check->msg = g_strdup ("[xaccTransEqual] descriptions differ: salt pork vs Waldo Pepper");
     g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
@@ -871,8 +871,8 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
 
     xaccTransBeginEdit (clone);
     cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
-    g_free(clone->description);
-    clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
+    CACHE_REMOVE(clone->description);
+    clone->description = CACHE_INSERT ("Waldo Pepper");
     auto frame = qof_instance_get_slots (QOF_INSTANCE (clone));
     frame->set({"qux", "quux", "corge"}, new KvpValue(654.321));
     xaccTransCommitEdit (clone);
@@ -885,7 +885,7 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (check->hits, ==, 9);
     xaccTransBeginEdit (clone);
     cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
-    clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
+    clone->description = CACHE_INSERT ("Waldo Pepper");
     frame->set({"qux", "quux", "corge"}, new KvpValue(123.456));
     xaccTransCommitEdit (clone);
     g_free (cleanup->msg);
@@ -975,8 +975,8 @@ test_xaccTransGetImbalanceValue (Fixture *fixture, gconstpointer pData)
     g_assert (gnc_numeric_equal (xaccTransGetImbalanceValue (fixture->txn),
                                  gnc_numeric_zero ()));
     split1->acc = fixture->acc1;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (100000, 1000);
     split1->value = gnc_numeric_create (3200, 240);
     xaccTransBeginEdit (fixture->txn);
@@ -1001,8 +1001,8 @@ test_xaccTransGetImbalance (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (g_list_length (mlist), ==, 0);
 
     split1->acc = fixture->acc1;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (100000, 1000);
     split1->value = gnc_numeric_create (3200, 240);
     xaccTransBeginEdit (fixture->txn);
@@ -1043,13 +1043,13 @@ test_xaccTransGetImbalance_trading (Fixture *fixture,
     g_assert (!xaccTransIsBalanced (fixture->txn));
     /* Make it look like a proper trading accounts transactionm */
     split1->acc = acc1;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (-10000, 100);
     split1->value = gnc_numeric_create (-3200, 240);
     split2->acc = acc2;
-    split2->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split2->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split2->memo = CACHE_INSERT ("foo");
+    split2->action = CACHE_INSERT ("bar");
     split2->amount = gnc_numeric_create (3000, 240);
     split2->value = gnc_numeric_create (3200, 240);
     xaccTransBeginEdit (fixture->txn);
@@ -1091,8 +1091,8 @@ test_xaccTransIsBalanced (Fixture *fixture, gconstpointer pData)
     g_assert (xaccTransIsBalanced (fixture->txn));
 
     split1->acc = fixture->acc1;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (100000, 1000);
     split1->value = gnc_numeric_create (3200, 240);
     xaccTransBeginEdit (fixture->txn);
@@ -1124,13 +1124,13 @@ test_xaccTransIsBalanced_trading (Fixture *fixture, gconstpointer pData)
     /* The setup transaction is unbalanced in a trading-accounts environment. */
     g_assert (!xaccTransIsBalanced (fixture->txn));
     split1->acc = acc1;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (3200, 240);
     split1->value = gnc_numeric_create (3200, 240);
     split2->acc = acc2;
-    split2->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split2->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split2->memo = CACHE_INSERT ("foo");
+    split2->action = CACHE_INSERT ("bar");
     split2->amount = gnc_numeric_create (-10000, 100);
     split2->value = gnc_numeric_create (-3000, 240);
     xaccTransBeginEdit (fixture->txn);
@@ -1592,8 +1592,8 @@ test_xaccTransCommitEdit (void)
     xaccAccountSetCommodity (acc1, comm);
     xaccAccountSetCommodity (acc2, curr);
     txn->date_posted = posted;
-    split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
-    split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
+    split1->memo = CACHE_INSERT ("foo");
+    split1->action = CACHE_INSERT ("bar");
     split1->amount = gnc_numeric_create (100000, 1000);
     split1->value = gnc_numeric_create (3200, 240);
     /* Note, deliberately imblanced to force xaccTransScrubImbalance
@@ -1603,8 +1603,8 @@ test_xaccTransCommitEdit (void)
     split2->value = gnc_numeric_create (-3000, 240);
     split1->acc = acc1;
     split2->acc = acc2;
-    txn->num = static_cast<char*>(CACHE_INSERT ("123"));
-    txn->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
+    txn->num = CACHE_INSERT ("123");
+    txn->description = CACHE_INSERT ("Waldo Pepper");
     xaccTransBeginEdit (txn);
     {
         xaccTransSetCurrency (txn, curr);
@@ -1664,8 +1664,8 @@ test_xaccTransRollbackEdit (Fixture *fixture, gconstpointer pData)
     orig = txn->orig;
     base_frame = orig->inst.kvp_data; /* DupeTransaction copies the kvp_frame */
     g_object_ref (orig); /* Keep rollback from actually freeing it */
-    txn->num = static_cast<char*>(CACHE_INSERT("321"));
-    txn->description = static_cast<char*>(CACHE_INSERT("salt peanuts"));
+    txn->num = CACHE_INSERT("321");
+    txn->description = CACHE_INSERT("salt peanuts");
     txn->common_currency = NULL;
     txn->inst.kvp_data = NULL;
     txn->date_entered = new_entered;
@@ -1757,19 +1757,19 @@ test_xaccTransOrder_num_action (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, NULL, NULL), ==, 0);
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==,
                      qof_instance_guid_compare (txnA, txnB));
-    txnB->description = static_cast<char*>(CACHE_INSERT ("Salt Peanuts"));
+    txnB->description = CACHE_INSERT ("Salt Peanuts");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), >=, 1);
     txnB->date_entered += 1;
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
-    txnB->num = static_cast<char*>(CACHE_INSERT ("101"));
+    txnB->num = CACHE_INSERT ("101");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
-    txnA->num = static_cast<char*>(CACHE_INSERT ("12a"));
+    txnA->num = CACHE_INSERT ("12a");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
-    txnB->num = static_cast<char*>(CACHE_INSERT ("12c"));
+    txnB->num = CACHE_INSERT ("12c");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
-    txnB->num = static_cast<char*>(CACHE_INSERT ("12"));
+    txnB->num = CACHE_INSERT ("12");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
-    txnB->num = static_cast<char*>(CACHE_INSERT ("one-oh-one"));
+    txnB->num = CACHE_INSERT ("one-oh-one");
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
     g_assert_cmpint (xaccTransOrder_num_action (txnA, "24", txnB, "42"), ==, -1);
     txnB->date_posted -= 1;

commit 4132939612aff073f3d2afab77171b9c9d59881d
Author: Simon Arlott <sa.me.uk>
Date:   Sun Jul 11 18:51:41 2021 +0100

    Avoid leaking string cache entries for "" in Transaction and Split
    
    When g_object_new() is used, the strings that default to "" are added to
    the string cache. These are then not correctly removed when updating them
    with new values when cloning a Transaction/Split.
    
    Use CACHE_REPLACE instead of CACHE_INSERT.

diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index 8fb6091fa..5ca91507b 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -564,8 +564,8 @@ xaccDupeSplit (const Split *s)
     split->orig_acc = s->orig_acc;
     split->lot = s->lot;
 
-    split->memo = CACHE_INSERT(s->memo);
-    split->action = CACHE_INSERT(s->action);
+    CACHE_REPLACE(split->memo, s->memo);
+    CACHE_REPLACE(split->action, s->action);
 
     qof_instance_copy_kvp (QOF_INSTANCE (split), QOF_INSTANCE (s));
 
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index e7c3cba0a..9db75799a 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -602,8 +602,8 @@ dupe_trans (const Transaction *from)
 
     to = g_object_new (GNC_TYPE_TRANSACTION, NULL);
 
-    to->num         = CACHE_INSERT (from->num);
-    to->description = CACHE_INSERT (from->description);
+    CACHE_REPLACE (to->num, from->num);
+    CACHE_REPLACE (to->description, from->description);
 
     to->splits = g_list_copy (from->splits);
     for (node = to->splits; node; node = node->next)
@@ -647,8 +647,8 @@ xaccTransCloneNoKvp (const Transaction *from)
 
     to->date_entered    = from->date_entered;
     to->date_posted     = from->date_posted;
-    to->num             = CACHE_INSERT (from->num);
-    to->description     = CACHE_INSERT (from->description);
+    CACHE_REPLACE (to->num, from->num);
+    CACHE_REPLACE (to->description, from->description);
     to->common_currency = from->common_currency;
     qof_instance_copy_version(to, from);
     qof_instance_copy_version_check(to, from);

commit bf8fe1123c6acad373514ba8160727cdd0501e52
Author: Simon Arlott <sa.me.uk>
Date:   Sun Jul 11 15:04:43 2021 +0100

    Commit root accounts after loading from XML
    
    The root accounts start with a non-zero editlevel because BeginEdit is
    called for them during loading but not committed after loading.
    
    If the book is then closed without performing any further edits that would
    require a commit, the Account book_end process does nothing because the
    root account is still being edited and so none of the accounts are freed.

diff --git a/libgnucash/backend/xml/io-gncxml-v2.cpp b/libgnucash/backend/xml/io-gncxml-v2.cpp
index c956c8db5..d5b438be7 100644
--- a/libgnucash/backend/xml/io-gncxml-v2.cpp
+++ b/libgnucash/backend/xml/io-gncxml-v2.cpp
@@ -699,6 +699,7 @@ qof_session_load_from_xml_file_v2_full (
     QofBookFileType type)
 {
     Account* root;
+    Account* template_root;
     sixtp_gdv2* gd;
     sixtp* top_parser;
     sixtp* main_parser;
@@ -851,12 +852,18 @@ qof_session_load_from_xml_file_v2_full (
     /* commit all groups, this completes the BeginEdit started when the
      * account_end_handler finished reading the account.
      */
+    template_root = gnc_book_get_template_root (book);
     gnc_account_foreach_descendant (root,
                                     (AccountCb) xaccAccountCommitEdit,
                                     NULL);
-    gnc_account_foreach_descendant (gnc_book_get_template_root (book),
+    gnc_account_foreach_descendant (template_root,
                                     (AccountCb) xaccAccountCommitEdit,
                                     NULL);
+    /* if these exist in the XML file then they will be uncommitted */
+    if (qof_instance_get_editlevel(root) != 0)
+        xaccAccountCommitEdit(root);
+    if (qof_instance_get_editlevel(template_root) != 0)
+        xaccAccountCommitEdit(template_root);
 
     /* start logging again */
     xaccLogEnable ();
diff --git a/libgnucash/backend/xml/test/test-load-xml2.cpp b/libgnucash/backend/xml/test/test-load-xml2.cpp
index 945470078..455d20216 100644
--- a/libgnucash/backend/xml/test/test-load-xml2.cpp
+++ b/libgnucash/backend/xml/test/test-load-xml2.cpp
@@ -108,6 +108,9 @@ test_load_file (const char* filename)
     do_test (gnc_account_get_book (root) == book,
              "book and root account don't match");
 
+    do_test (qof_instance_get_editlevel(root) == 0,
+             "root account editlevel is not 0");
+
     do_test_args (qof_session_get_error (session) == ERR_BACKEND_NO_ERR,
                   "session load xml2", __FILE__, __LINE__,
                   "qof error=%d for file [%s]",

commit f15402a9a603f0cb8e70f8ff89a5235e8be494f5
Author: Simon Arlott <sa.me.uk>
Date:   Sun Jul 11 14:53:57 2021 +0100

    Load test data from XML properly
    
    If qof_session_new() is called without a book then qof_session_load()
    won't do anything.
    
    Set up a book for it to use.

diff --git a/libgnucash/backend/xml/test/test-load-xml2.cpp b/libgnucash/backend/xml/test/test-load-xml2.cpp
index 945470078..8eaf19749 100644
--- a/libgnucash/backend/xml/test/test-load-xml2.cpp
+++ b/libgnucash/backend/xml/test/test-load-xml2.cpp
@@ -92,7 +92,8 @@ test_load_file (const char* filename)
     g_log_set_handler (logdomain, loglevel,
                        (GLogFunc)test_checked_handler, &check);
 
-    auto session = qof_session_new (nullptr);
+    auto book = qof_book_new();
+    auto session = qof_session_new (book);
 
     remove_locks (filename);
 
@@ -102,7 +103,6 @@ test_load_file (const char* filename)
                        ignore_lock ? SESSION_READ_ONLY : SESSION_NORMAL_OPEN);
 
     qof_session_load (session, NULL);
-    auto book = qof_session_get_book (session);
 
     auto root = gnc_book_get_root_account (book);
     do_test (gnc_account_get_book (root) == book,
@@ -115,6 +115,7 @@ test_load_file (const char* filename)
     /* Uncomment the line below to generate corrected files */
     /*    qof_session_save( session, NULL ); */
     qof_session_end (session);
+    qof_book_destroy (book);
 }
 
 int



Summary of changes:
 gnucash/gnome-utils/dialog-commodity.c         |  2 +
 gnucash/gnome-utils/gnc-component-manager.c    |  4 +-
 libgnucash/backend/xml/io-gncxml-v2.cpp        |  9 ++-
 libgnucash/backend/xml/test/test-load-xml2.cpp |  8 ++-
 libgnucash/engine/Account.cpp                  | 20 +++----
 libgnucash/engine/AccountP.h                   |  6 +-
 libgnucash/engine/Split.c                      |  6 +-
 libgnucash/engine/SplitP.h                     |  8 +--
 libgnucash/engine/Transaction.c                | 21 +++----
 libgnucash/engine/TransactionP.h               |  4 +-
 libgnucash/engine/gnc-budget.c                 |  4 +-
 libgnucash/engine/gnc-commodity.c              | 26 ++++-----
 libgnucash/engine/gnc-pricedb-p.h              |  2 +-
 libgnucash/engine/gnc-pricedb.c                |  6 +-
 libgnucash/engine/gncAddress.c                 | 26 ++++-----
 libgnucash/engine/gncBillTerm.c                | 10 +---
 libgnucash/engine/gncCustomer.c                | 12 ++--
 libgnucash/engine/gncEmployee.c                | 14 ++---
 libgnucash/engine/gncEntry.c                   | 12 ++--
 libgnucash/engine/gncInvoice.c                 | 12 ++--
 libgnucash/engine/gncJob.c                     | 12 ++--
 libgnucash/engine/gncOrder.c                   | 26 ++++-----
 libgnucash/engine/gncTaxTable.c                |  8 +--
 libgnucash/engine/gncVendor.c                  | 12 ++--
 libgnucash/engine/kvp-frame.cpp                |  2 +-
 libgnucash/engine/qof-string-cache.cpp         | 13 +++--
 libgnucash/engine/qof-string-cache.h           |  6 +-
 libgnucash/engine/qofbook.cpp                  |  2 +-
 libgnucash/engine/test/test-qof-string-cache.c |  8 +--
 libgnucash/engine/test/utest-Account.cpp       |  4 +-
 libgnucash/engine/test/utest-Split.cpp         |  4 +-
 libgnucash/engine/test/utest-Transaction.cpp   | 78 +++++++++++++-------------
 32 files changed, 181 insertions(+), 206 deletions(-)



More information about the gnucash-changes mailing list