gnucash unstable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Sat Apr 14 13:22:35 EDT 2018


Updated	 via  https://github.com/Gnucash/gnucash/commit/f680823d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/01420adb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e90a662a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b7396611 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9b643574 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e4d0ad9d (commit)
	from  https://github.com/Gnucash/gnucash/commit/a39ba167 (commit)



commit f680823dbfff5cc90c98139c755c727f2f19d4cb
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Apr 13 14:02:57 2018 -0700

    Bug 795039 - Crash on startup using Technicolor Style sheet in report
    
    The mingw-w64 toolchain bizarrely substitutes scm_to_locale_string()
    for scm_to_utf8_string(). This results in latin1 (yeah, "locale" is
    a lie) instead of utf8 which causes an assertion in
    g_utf8_collate_key().
    
    Perhaps equally bizarre, the compiler doesn't make the substitution
    with scm_to_utf8_stringn(), so use that instead.

diff --git a/libgnucash/app-utils/gnc-ui-util.c b/libgnucash/app-utils/gnc-ui-util.c
index c4e3a86..5fa6430 100644
--- a/libgnucash/app-utils/gnc-ui-util.c
+++ b/libgnucash/app-utils/gnc-ui-util.c
@@ -590,13 +590,13 @@ gnc_ui_account_get_tax_info_string (const Account *account)
             {
                 gchar *form = NULL;
 
-                /* Note: using scm_to_utf8_string directly here instead
+                /* Note: using scm_to_utf8_stringn directly here instead
                    of our wrapper gnc_scm_to_utf8_string. 'form' should
                    be freed with 'free' instead of 'g_free'. This will
                    be taken care of automatically during scm_dynwind_end,
                    because we inform guile of this memory allocation via
                    scm_dynwind_free a little further. */
-                form = scm_to_utf8_string (form_scm);
+                form = scm_to_utf8_stringn (form_scm, NULL);
                 if (!form)
                 {
                     if (tax_related)
diff --git a/libgnucash/core-utils/gnc-guile-utils.c b/libgnucash/core-utils/gnc-guile-utils.c
index e86fe9f..99e46d7 100644
--- a/libgnucash/core-utils/gnc-guile-utils.c
+++ b/libgnucash/core-utils/gnc-guile-utils.c
@@ -43,7 +43,7 @@ gchar *gnc_scm_to_utf8_string(SCM scm_string)
         gchar* s;
         char * str;
 
-        str = scm_to_utf8_string(scm_string);
+        str = scm_to_utf8_stringn(scm_string, NULL);
         s = g_strdup(str);
         free (str);
         return s;

commit 01420adb9989f49a0413b4a9bbf34494623a5443
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Mar 24 16:30:34 2018 -0700

    Bug 772776 - VERY large queries (over 11000 fields in IN clause) slow...
    
    down GnuCash
    
    Replace with joins or subqueries. Affords a 20% speedup on Windows.

diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index ab2d6e4..ca719f3 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -821,44 +821,6 @@ load_slot_for_list_item (GncSqlBackend* sql_be, GncSqlRow& row,
 
 }
 
-void
-gnc_sql_slots_load_for_instancevec (GncSqlBackend* sql_be, InstanceVec& instances)
-{
-    QofCollection* coll;
-    std::stringstream sql;
-
-    g_return_if_fail (sql_be != NULL);
-
-    // Ignore empty list
-    if (instances.empty()) return;
-
-    coll = qof_instance_get_collection (instances[0]);
-
-    // Create the query for all slots for all items on the list
-
-    sql << "SELECT * FROM " << TABLE_NAME << " WHERE " <<
-                            obj_guid_col_table[0]->name();
-    if (instances.size() != 1)
-        sql << " IN (";
-    else
-        sql << " = ";
-
-    gnc_sql_append_guids_to_sql (sql, instances);
-    if (instances.size() > 1)
-        sql << ")";
-
-    // Execute the query and load the slots
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
-    if (stmt == nullptr)
-    {
-        PERR ("stmt == NULL, SQL = '%s'\n", sql.str().c_str());
-        return;
-    }
-    auto result = sql_be->execute_select_statement (stmt);
-    for (auto row : *result)
-        load_slot_for_list_item (sql_be, row, coll);
-}
-
 static void
 load_slot_for_book_object (GncSqlBackend* sql_be, GncSqlRow& row,
                            BookLookupFn lookup_fn)
diff --git a/libgnucash/backend/sql/gnc-slots-sql.h b/libgnucash/backend/sql/gnc-slots-sql.h
index 0cdf3a6..b7b9891 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.h
+++ b/libgnucash/backend/sql/gnc-slots-sql.h
@@ -76,17 +76,6 @@ gboolean gnc_sql_slots_delete (GncSqlBackend* sql_be, const GncGUID* guid);
  */
 void gnc_sql_slots_load (GncSqlBackend* sql_be, QofInstance* inst);
 
-/**
- * gnc_sql_slots_load_for_instancevec - Loads slots for a set of QofInstance*
- * from the db.  Loading slots for a set is faster than loading for one object
- * at a time because fewer SQL queries are used.
- *
- * @param sql_be SQL backend
- * @param list List of objects
- */
-void gnc_sql_slots_load_for_instancevec (GncSqlBackend* sql_be,
-                                         InstanceVec& instances);
-
 typedef QofInstance* (*BookLookupFn) (const GncGUID* guid,
                                       const QofBook* book);
 
diff --git a/libgnucash/backend/sql/gnc-sql-backend.cpp b/libgnucash/backend/sql/gnc-sql-backend.cpp
index 1a8af92..536b76b 100644
--- a/libgnucash/backend/sql/gnc-sql-backend.cpp
+++ b/libgnucash/backend/sql/gnc-sql-backend.cpp
@@ -510,19 +510,19 @@ GncSqlBackend::sync(QofBook* book)
 void
 GncSqlBackend::begin(QofInstance* inst)
 {
-    g_return_if_fail (inst != NULL);
+    //g_return_if_fail (inst != NULL);
 
-    ENTER (" ");
-    LEAVE ("");
+    //ENTER (" ");
+    //LEAVE ("");
 }
 
 void
 GncSqlBackend::rollback(QofInstance* inst)
 {
-    g_return_if_fail (inst != NULL);
+    //g_return_if_fail (inst != NULL);
 
-    ENTER (" ");
-    LEAVE ("");
+    //ENTER (" ");
+    //LEAVE ("");
 }
 
 void
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index 5d94e69..ca8cb97 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -247,52 +247,36 @@ load_single_split (GncSqlBackend* sql_be, GncSqlRow& row)
     }
     return pSplit;
 }
-
-static void
-load_splits_for_sql_subquery (GncSqlBackend* sql_be, std::string subquery)
-{
-    g_return_if_fail (sql_be != NULL);
-    const std::string sskey(tx_guid_col_table[0]->name());
-    std::string sql("SELECT * FROM " SPLIT_TABLE " WHERE ");
-    sql += sskey + " IN (" + subquery + ")";
-    auto stmt = sql_be->create_statement_from_sql(sql);
-    auto result = sql_be->execute_select_statement(stmt);
-    for (auto row : *result)
-        load_single_split (sql_be, row);
-    const std::string spkey(split_col_table[0]->name());
-    std::string sub_subquery("SELECT DISTINCT ");
-    sub_subquery += spkey + " FROM " SPLIT_TABLE " WHERE " + sskey +
-        " IN (" + subquery + ")";
-    gnc_sql_slots_load_for_sql_subquery(sql_be, sub_subquery,
-                                        (BookLookupFn)xaccSplitLookup);
-}
-
 static void
-load_splits_for_tx_list (GncSqlBackend* sql_be, InstanceVec& transactions)
+load_splits_for_transactions (GncSqlBackend* sql_be, std::string selector)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
+    const std::string spkey(split_col_table[0]->name());
+    const std::string sskey(tx_guid_col_table[0]->name());
+    const std::string tpkey(tx_col_table[0]->name());
 
-    sql << "SELECT * FROM " << SPLIT_TABLE << " WHERE " <<
-        tx_guid_col_table[0]->name() << " IN (";
-    gnc_sql_append_guids_to_sql (sql, transactions);
-    sql << ")";
+    std::string sql("SELECT ");
+    if (selector.empty())
+    {
+	sql += SPLIT_TABLE ".* FROM " SPLIT_TABLE " INNER JOIN "
+	    TRANSACTION_TABLE " WHERE " SPLIT_TABLE "." + sskey + " = "
+	    TRANSACTION_TABLE "." + tpkey;
+	selector = "(SELECT DISTINCT " + tpkey + " FROM " TRANSACTION_TABLE ")";
+    }
+    else
+	sql += " * FROM " SPLIT_TABLE " WHERE " + sskey + " IN " + selector;
 
     // Execute the query and load the splits
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement (stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         Split* s = load_single_split (sql_be, row);
-        if (s != nullptr)
-            instances.push_back(QOF_INSTANCE(s));
-    }
-
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    sql = "SELECT DISTINCT ";
+    sql += spkey + " FROM " SPLIT_TABLE " WHERE " + sskey + " IN " + selector;
+    gnc_sql_slots_load_for_sql_subquery(sql_be, sql,
+					(BookLookupFn)xaccSplitLookup);
 }
 
 static  Transaction*
@@ -356,19 +340,30 @@ typedef struct
  * @param stmt SQL statement
  */
 static void
-query_transactions (GncSqlBackend* sql_be, const GncSqlStatementPtr& stmt)
+query_transactions (GncSqlBackend* sql_be, std::string selector)
 {
     g_return_if_fail (sql_be != NULL);
-    g_return_if_fail (stmt != NULL);
 
+    const std::string tpkey(tx_col_table[0]->name());
+    std::string sql("SELECT * FROM " TRANSACTION_TABLE);
+
+    if (!selector.empty() && selector[0] == '(')
+	sql += " WHERE " + tpkey + " IN " + selector;
+    else if (!selector.empty()) // plain condition
+	sql += " WHERE " + selector;
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
     if (result->begin() == result->end())
+    {
+	PINFO("Query %s returned no results", sql.c_str());
         return;
-
+    }
+    
     Transaction* tx;
 
     // Load the transactions
     InstanceVec instances;
+    instances.reserve(result->size());
     for (auto row : *result)
     {
         tx = load_single_tx (sql_be, row);
@@ -382,8 +377,15 @@ query_transactions (GncSqlBackend* sql_be, const GncSqlStatementPtr& stmt)
     // Load all splits and slots for the transactions
     if (!instances.empty())
     {
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
-        load_splits_for_tx_list (sql_be, instances);
+	const std::string tpkey(tx_col_table[0]->name());
+	if (selector.empty())
+	{
+	    selector = "(SELECT DISTINCT ";
+	    selector += tpkey + " FROM " TRANSACTION_TABLE +")";
+	}
+        load_splits_for_transactions (sql_be, selector);
+        gnc_sql_slots_load_for_sql_subquery (sql_be, selector,
+					     (BookLookupFn)xaccTransLookup);
     }
 
     // Commit all of the transactions
@@ -691,16 +693,15 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* sql_be,
     g_return_if_fail (account != NULL);
 
     guid = qof_instance_get_guid (QOF_INSTANCE (account));
-    (void)guid_to_string_buff (guid, guid_buf);
-    query_sql = g_strdup_printf (
-                    "SELECT DISTINCT t.* FROM %s AS t, %s AS s WHERE s.tx_guid=t.guid AND s.account_guid ='%s'",
-                    TRANSACTION_TABLE, SPLIT_TABLE, guid_buf);
-    auto stmt = sql_be->create_statement_from_sql(query_sql);
-    g_free (query_sql);
-    if (stmt != nullptr)
-    {
-        query_transactions (sql_be, stmt);
-    }
+
+    const std::string tpkey(tx_col_table[0]->name());    //guid
+    const std::string spkey(split_col_table[0]->name()); //guid
+    const std::string stkey(split_col_table[1]->name()); //txn_guid
+    const std::string sakey(split_col_table[2]->name()); //account_guid
+    std::string sql("(SELECT DISTINCT ");
+    sql += stkey + " FROM " SPLIT_TABLE " WHERE " + sakey + " = '";
+    sql += gnc::GUID(*guid).to_string() + "')";
+    query_transactions (sql_be, sql);
 }
 
 /**
@@ -713,44 +714,7 @@ void
 GncSqlTransBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
-
-    std::string query_sql("SELECT * FROM " TRANSACTION_TABLE);
-    auto stmt = sql_be->create_statement_from_sql(query_sql);
-
-    if (stmt != nullptr)
-    {
-        auto result = sql_be->execute_select_statement(stmt);
-        if (result->begin() == result->end())
-            return;
-
-        Transaction* tx;
-
-        // Load the transactions
-        InstanceVec instances;
-        instances.reserve(result->size());
-        for (auto row : *result)
-        {
-            tx = load_single_tx (sql_be, row);
-            if (tx != nullptr)
-            {
-                xaccTransScrubPostedDate (tx);
-                instances.push_back(QOF_INSTANCE(tx));
-            }
-        }
-        if (instances.empty())
-            return;
-        const std::string tpkey(tx_col_table[0]->name());
-        std::string subquery("SELECT DISTINCT ");
-        subquery += tpkey + " FROM " TRANSACTION_TABLE;
-        gnc_sql_slots_load_for_sql_subquery (sql_be, subquery,
-                                             (BookLookupFn)xaccTransLookup);
-        load_splits_for_sql_subquery (sql_be, subquery);
-
-        // Commit all of the transactions
-        for (auto instance : instances)
-            xaccTransCommitEdit(GNC_TRANSACTION(instance));
-
-    }
+    query_transactions (sql_be, "");
 }
 
 static void
@@ -995,12 +959,11 @@ GncSqlColumnTableEntryImpl<CT_TXREF>::load (const GncSqlBackend* sql_be,
             tx = xaccTransLookup (&guid, sql_be->book());
 
         // If the transaction is not found, try loading it
+	std::string tpkey(tx_col_table[0]->name());
         if (tx == nullptr)
         {
-            auto buf = std::string{"SELECT * FROM "} + TRANSACTION_TABLE +
-                                       " WHERE guid='" + val + "'";
-            auto stmt = sql_be->create_statement_from_sql (buf);
-            query_transactions ((GncSqlBackend*)sql_be, stmt);
+	    std::string sql = tpkey + " = '" + val + "'";
+            query_transactions ((GncSqlBackend*)sql_be, sql);
             tx = xaccTransLookup (&guid, sql_be->book());
         }
 
diff --git a/libgnucash/engine/TransLog.c b/libgnucash/engine/TransLog.c
index 7584bc0..b88d982 100644
--- a/libgnucash/engine/TransLog.c
+++ b/libgnucash/engine/TransLog.c
@@ -230,7 +230,7 @@ xaccTransWriteLog (Transaction *trans, char flag)
 
     if (!gen_logs)
     {
-	 PINFO ("Attempt to write disabled transaction log");
+         PINFO ("Attempt to write disabled transaction log");
 	 return;
     }
     if (!trans_log) return;

commit e90a662a20299d5cbd649cc855cb491a3d9dc228
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Mar 26 16:59:49 2018 -0700

    Use subquery instead of instancevec GncSqlTransBackend::load_all.

diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index 6013aaa..5d94e69 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -249,6 +249,25 @@ load_single_split (GncSqlBackend* sql_be, GncSqlRow& row)
 }
 
 static void
+load_splits_for_sql_subquery (GncSqlBackend* sql_be, std::string subquery)
+{
+    g_return_if_fail (sql_be != NULL);
+    const std::string sskey(tx_guid_col_table[0]->name());
+    std::string sql("SELECT * FROM " SPLIT_TABLE " WHERE ");
+    sql += sskey + " IN (" + subquery + ")";
+    auto stmt = sql_be->create_statement_from_sql(sql);
+    auto result = sql_be->execute_select_statement(stmt);
+    for (auto row : *result)
+        load_single_split (sql_be, row);
+    const std::string spkey(split_col_table[0]->name());
+    std::string sub_subquery("SELECT DISTINCT ");
+    sub_subquery += spkey + " FROM " SPLIT_TABLE " WHERE " + sskey +
+        " IN (" + subquery + ")";
+    gnc_sql_slots_load_for_sql_subquery(sql_be, sub_subquery,
+                                        (BookLookupFn)xaccSplitLookup);
+}
+
+static void
 load_splits_for_tx_list (GncSqlBackend* sql_be, InstanceVec& transactions)
 {
     g_return_if_fail (sql_be != NULL);
@@ -695,12 +714,42 @@ GncSqlTransBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    auto query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
+    std::string query_sql("SELECT * FROM " TRANSACTION_TABLE);
     auto stmt = sql_be->create_statement_from_sql(query_sql);
-    g_free (query_sql);
+
     if (stmt != nullptr)
     {
-        query_transactions (sql_be, stmt);
+        auto result = sql_be->execute_select_statement(stmt);
+        if (result->begin() == result->end())
+            return;
+
+        Transaction* tx;
+
+        // Load the transactions
+        InstanceVec instances;
+        instances.reserve(result->size());
+        for (auto row : *result)
+        {
+            tx = load_single_tx (sql_be, row);
+            if (tx != nullptr)
+            {
+                xaccTransScrubPostedDate (tx);
+                instances.push_back(QOF_INSTANCE(tx));
+            }
+        }
+        if (instances.empty())
+            return;
+        const std::string tpkey(tx_col_table[0]->name());
+        std::string subquery("SELECT DISTINCT ");
+        subquery += tpkey + " FROM " TRANSACTION_TABLE;
+        gnc_sql_slots_load_for_sql_subquery (sql_be, subquery,
+                                             (BookLookupFn)xaccTransLookup);
+        load_splits_for_sql_subquery (sql_be, subquery);
+
+        // Commit all of the transactions
+        for (auto instance : instances)
+            xaccTransCommitEdit(GNC_TRANSACTION(instance));
+
     }
 }
 

commit b739661171edad92c678b5bbf6e5814c34518a24
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Mar 25 10:19:44 2018 -0700

    Remove functions marked G_UNUSED.
    
    More noise reduction.

diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index e54728c..6013aaa 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -872,199 +872,6 @@ typedef struct
     gboolean has_been_run;
 } split_query_info_t;
 
-#define TX_GUID_CHECK 0
-
-G_GNUC_UNUSED static  gpointer
-compile_split_query (GncSqlBackend* sql_be, QofQuery* query)
-{
-    split_query_info_t* query_info = NULL;
-    gchar* query_sql;
-
-    g_return_val_if_fail (sql_be != NULL, NULL);
-    g_return_val_if_fail (query != NULL, NULL);
-
-    query_info = static_cast<decltype (query_info)> (
-                     g_malloc (sizeof (split_query_info_t)));
-    g_assert (query_info != NULL);
-    query_info->has_been_run = FALSE;
-
-    if (qof_query_has_terms (query))
-    {
-        GList* orterms = qof_query_get_terms (query);
-        GList* orTerm;
-        std::stringstream sql;
-        gboolean need_OR = FALSE;
-
-        for (orTerm = orterms; orTerm != NULL; orTerm = orTerm->next)
-        {
-            GList* andterms = (GList*)orTerm->data;
-            GList* andTerm;
-            gboolean need_AND = FALSE;
-#if TX_GUID_CHECK
-            gboolean has_tx_guid_check = FALSE;
-#endif
-            if (need_OR)
-            {
-                sql << " OR ";
-            }
-            sql << "(";
-            for (andTerm = andterms; andTerm != NULL; andTerm = andTerm->next)
-            {
-                QofQueryTerm* term;
-                GSList* paramPath;
-                gboolean unknownPath = FALSE;
-
-                term = (QofQueryTerm*)andTerm->data;
-                paramPath = qof_query_term_get_param_path (term);
-                const char* path = static_cast<decltype (path)> (paramPath->data);
-                const char* next_path =
-                    static_cast<decltype (next_path)> (paramPath->next->data);
-                if (strcmp (path, QOF_PARAM_BOOK) == 0) continue;
-
-#if SIMPLE_QUERY_COMPILATION
-                if (strcmp (path, SPLIT_ACCOUNT) != 0 ||
-                    strcmp (next_path, QOF_PARAM_GUID) != 0) continue;
-#endif
-
-                if (need_AND) sql<< " AND ";
-
-                if (strcmp (path, SPLIT_ACCOUNT) == 0 &&
-                    strcmp (next_path, QOF_PARAM_GUID) == 0)
-                {
-                    convert_query_term_to_sql (sql_be, "s.account_guid", term,
-                                               sql);
-#if SIMPLE_QUERY_COMPILATION
-                    goto done_compiling_query;
-#endif
-
-                }
-                else if (strcmp (path, SPLIT_RECONCILE) == 0)
-                {
-                    convert_query_term_to_sql (sql_be, "s.reconcile_state",
-                                               term, sql);
-
-                }
-                else if (strcmp (path, SPLIT_TRANS) == 0)
-                {
-#if TX_GUID_CHECK
-                    if (!has_tx_guid_check)
-                    {
-                        sql << "(splits.tx_guid = transactions.guid) AND ");
-                        has_tx_guid_check = TRUE;
-                    }
-#endif
-                    if (strcmp (next_path, TRANS_DATE_POSTED) == 0)
-                    {
-                        convert_query_term_to_sql (sql_be, "t.post_date", term,
-                                                   sql);
-                    }
-                    else if (strcmp (next_path, TRANS_DESCRIPTION) == 0)
-                    {
-                        convert_query_term_to_sql (sql_be, "t.description",
-                                                   term, sql);
-                    }
-                    else
-                    {
-                        unknownPath = TRUE;
-                    }
-
-                }
-                else if (strcmp (path, SPLIT_VALUE) == 0)
-                {
-                    convert_query_term_to_sql (sql_be,
-                                               "s.value_num/s.value_denom",
-                                               term, sql);
-                }
-                else
-                {
-                    unknownPath = TRUE;
-                }
-
-                if (unknownPath)
-                {
-                    std::stringstream name;
-                    name << static_cast<char*>(paramPath->data);
-                    for (;paramPath->next != NULL; paramPath = paramPath->next)
-                    {
-                        next_path =
-                            static_cast<decltype (next_path)>(paramPath->next->data);
-                        name << "." << next_path;
-                    }
-                    PERR ("Unknown SPLIT query field: %s\n",
-                          name.str().c_str());
-                }
-                need_AND = TRUE;
-            }
-
-            /* If the last char in the string is a '(', then for some reason, there were
-               no terms added to the SQL.  If so, remove it and ignore the OR term. */
-        if (!sql.str().empty() && sql.str().back() == '(')
-            {
-                sql.str().erase(sql.str().back());
-                need_OR = FALSE;
-            }
-            else
-            {
-                sql << ")";
-                need_OR = TRUE;
-            }
-        }
-
-#if SIMPLE_QUERY_COMPILATION
-done_compiling_query:
-#endif
-    if (!sql.str().empty())
-        {
-#if SIMPLE_QUERY_COMPILATION
-            sql<< ")";
-#endif
-            query_sql = g_strdup_printf (
-                            "SELECT DISTINCT t.* FROM %s AS t, %s AS s WHERE s.tx_guid=t.guid AND %s",
-                            TRANSACTION_TABLE, SPLIT_TABLE, sql.str().c_str());
-        }
-        else
-        {
-            query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
-        }
-        query_info->stmt = sql_be->create_statement_from_sql(query_sql);
-        g_free (query_sql);
-
-    }
-    else
-    {
-        query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
-        query_info->stmt = sql_be->create_statement_from_sql(query_sql);
-        g_free (query_sql);
-    }
-
-    return query_info;
-}
-
-G_GNUC_UNUSED static void
-run_split_query (GncSqlBackend* sql_be, gpointer pQuery)
-{
-    split_query_info_t* query_info = (split_query_info_t*)pQuery;
-
-    g_return_if_fail (sql_be != NULL);
-    g_return_if_fail (pQuery != NULL);
-
-    if (!query_info->has_been_run)
-    {
-        query_transactions (sql_be, query_info->stmt);
-        query_info->has_been_run = TRUE;
-        query_info->stmt = nullptr;
-    }
-}
-
-G_GNUC_UNUSED static void
-free_split_query (GncSqlBackend* sql_be, gpointer pQuery)
-{
-    g_return_if_fail (sql_be != NULL);
-    g_return_if_fail (pQuery != NULL);
-
-    g_free (pQuery);
-}
-
 /* ----------------------------------------------------------------- */
 typedef struct
 {
@@ -1118,22 +925,6 @@ static const EntryVec acct_balances_col_table
                                          (QofSetterFunc)set_acct_bal_balance),
 };
 
-G_GNUC_UNUSED static  single_acct_balance_t*
-load_single_acct_balances (const GncSqlBackend* sql_be, GncSqlRow& row)
-{
-    single_acct_balance_t* bal = NULL;
-
-    g_return_val_if_fail (sql_be != NULL, NULL);
-
-    bal = static_cast<decltype (bal)> (g_malloc (sizeof (single_acct_balance_t)));
-    g_assert (bal != NULL);
-
-    bal->sql_be = sql_be;
-    gnc_sql_load_object (sql_be, row, NULL, bal, acct_balances_col_table);
-
-    return bal;
-}
-
 /* ----------------------------------------------------------------- */
 template<> void
 GncSqlColumnTableEntryImpl<CT_TXREF>::load (const GncSqlBackend* sql_be,

commit 9b643574274c5f13093c6b4d3add25a6fc0f309f
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Mar 24 18:16:00 2018 -0700

    Remove LOAD_TRANSACTIONS_AS_NEEDED from SQL backend.
    
    We're not ready for that and until we are it's just noise.

diff --git a/libgnucash/backend/sql/gnc-account-sql.cpp b/libgnucash/backend/sql/gnc-account-sql.cpp
index e926b0d..f80370b 100644
--- a/libgnucash/backend/sql/gnc-account-sql.cpp
+++ b/libgnucash/backend/sql/gnc-account-sql.cpp
@@ -273,27 +273,6 @@ GncSqlAccountBackend::load_all (GncSqlBackend* sql_be)
 			     });
     }
 
-#if LOAD_TRANSACTIONS_AS_NEEDED
-    /* Load starting balances */
-    auto bal_slist = gnc_sql_get_account_balances_slist (sql_be);
-    for (auto bal = bal_slist; bal != NULL; bal = bal->next)
-    {
-        acct_balances_t* balances = (acct_balances_t*)bal->data;
-
-        qof_instance_increase_editlevel (balances->acct);
-        g_object_set (balances->acct,
-                      "start-balance", &balances->balance,
-                      "start-cleared-balance", &balances->cleared_balance,
-                      "start-reconciled-balance", &balances->reconciled_balance,
-                      NULL);
-
-        qof_instance_decrease_editlevel (balances->acct);
-    }
-    if (bal_slist != NULL)
-    {
-        g_slist_free (bal_slist);
-    }
-#endif
     LEAVE ("");
 }
 
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index 8f92178..e54728c 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -64,7 +64,6 @@ extern "C"
 #include "gnc-slots-sql.h"
 
 #define SIMPLE_QUERY_COMPILATION 1
-#define LOAD_TRANSACTIONS_AS_NEEDED 0
 
 static QofLogModule log_module = G_LOG_DOMAIN;
 
@@ -264,13 +263,17 @@ load_splits_for_tx_list (GncSqlBackend* sql_be, InstanceVec& transactions)
     // Execute the query and load the splits
     auto stmt = sql_be->create_statement_from_sql(sql.str());
     auto result = sql_be->execute_select_statement (stmt);
+    InstanceVec instances;
 
     for (auto row : *result)
+    {
         Split* s = load_single_split (sql_be, row);
-    sql = "SELECT DISTINCT ";
-    sql += spkey + " FROM " SPLIT_TABLE " WHERE " + sskey + " IN " + selector;
-    gnc_sql_slots_load_for_sql_subquery(sql_be, sql,
-					(BookLookupFn)xaccSplitLookup);
+        if (s != nullptr)
+            instances.push_back(QOF_INSTANCE(s));
+    }
+
+    if (!instances.empty())
+        gnc_sql_slots_load_for_instancevec (sql_be, instances);
 }
 
 static  Transaction*
@@ -344,19 +347,6 @@ query_transactions (GncSqlBackend* sql_be, const GncSqlStatementPtr& stmt)
         return;
 
     Transaction* tx;
-#if LOAD_TRANSACTIONS_AS_NEEDED
-    GSList* bal_list = NULL;
-    Account* root = gnc_book_get_root_account (sql_be->book());
-
-    qof_event_suspend ();
-    xaccAccountBeginEdit (root);
-
-    // Save the start/ending balances (balance, cleared and reconciled) for
-    // every account.
-    gnc_account_foreach_descendant (gnc_book_get_root_account (sql_be->primary_book),
-                                    save_account_balances,
-                                    &bal_list);
-#endif
 
     // Load the transactions
     InstanceVec instances;
@@ -381,71 +371,9 @@ query_transactions (GncSqlBackend* sql_be, const GncSqlStatementPtr& stmt)
     for (auto instance : instances)
          xaccTransCommitEdit(GNC_TRANSACTION(instance));
 
-#if LOAD_TRANSACTIONS_AS_NEEDED
-    // Update the account balances based on the loaded splits.  If the end
-    // balance has changed, update the start balance so that the end
-    // balance is the same as it was before the splits were loaded.
-    // Repeat for cleared and reconciled balances.
-    for (auto nextbal = bal_list; nextbal != NULL; nextbal = nextbal->next)
-    {
-        full_acct_balances_t* balns = (full_acct_balances_t*)nextbal->data;
-        gnc_numeric* pnew_end_bal;
-        gnc_numeric* pnew_end_c_bal;
-        gnc_numeric* pnew_end_r_bal;
-        gnc_numeric adj;
-
-        g_object_get (balns->acc,
-                      "end-balance", &pnew_end_bal,
-                      "end-cleared-balance", &pnew_end_c_bal,
-                      "end-reconciled-balance", &pnew_end_r_bal,
-                      NULL);
-
-        qof_instance_increase_editlevel (balns - acc);
-        if (!gnc_numeric_eq (*pnew_end_bal, balns->end_bal))
-        {
-            adj = gnc_numeric_sub (balns->end_bal, *pnew_end_bal,
-                                   GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            balns->start_bal = gnc_numeric_add (balns->start_bal, adj,
-                                                GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            g_object_set (balns->acc, "start-balance", &balns->start_bal, NULL);
-            qof_instance_decrease_editlevel (balns - acc);
-        }
-        if (!gnc_numeric_eq (*pnew_end_c_bal, balns->end_cleared_bal))
-        {
-            adj = gnc_numeric_sub (balns->end_cleared_bal, *pnew_end_c_bal,
-                                   GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            balns->start_cleared_bal = gnc_numeric_add (balns->start_cleared_bal, adj,
-                                                        GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            g_object_set (balns->acc, "start-cleared-balance", &balns->start_cleared_bal,
-                          NULL);
-        }
-        if (!gnc_numeric_eq (*pnew_end_r_bal, balns->end_reconciled_bal))
-        {
-            adj = gnc_numeric_sub (balns->end_reconciled_bal, *pnew_end_r_bal,
-                                   GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            balns->start_reconciled_bal = gnc_numeric_add (balns->start_reconciled_bal,
-                                                           adj,
-                                                           GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            g_object_set (balns->acc, "start-reconciled-balance",
-                          &balns->start_reconciled_bal, NULL);
-        }
-        qof_instance_decrease_editlevel (balns - acc);
-        xaccAccountRecomputeBalance (balns->acc);
-        g_free (pnew_end_bal);
-        g_free (pnew_end_c_bal);
-        g_free (pnew_end_r_bal);
-        g_free (balns);
-    }
-    if (bal_list != NULL)
-    {
-        g_slist_free (bal_list);
-    }
-
-    xaccAccountCommitEdit (root);
-    qof_event_resume ();
-#endif
 }
 
+
 /* ================================================================= */
 /**
  * Creates the transaction and split tables.
@@ -1206,89 +1134,6 @@ load_single_acct_balances (const GncSqlBackend* sql_be, GncSqlRow& row)
     return bal;
 }
 
-GSList*
-gnc_sql_get_account_balances_slist (GncSqlBackend* sql_be)
-{
-#if LOAD_TRANSACTIONS_AS_NEEDED
-    gchar* buf;
-    GSList* bal_slist = NULL;
-
-    g_return_val_if_fail (sql_be != NULL, NULL);
-
-    buf = g_strdup_printf ("SELECT account_guid, reconcile_state, sum(quantity_num) as quantity_num, quantity_denom FROM %s GROUP BY account_guid, reconcile_state, quantity_denom ORDER BY account_guid, reconcile_state",
-                           SPLIT_TABLE);
-    auto stmt = sql_be->create_statement_from_sql(buf);
-    g_assert (stmt != nullptr);
-    g_free (buf);
-    auto result = sql_be->execute_select_statement(stmt);
-    acct_balances_t* bal = NULL;
-
-    for (auto row : *result)
-    {
-        single_acct_balance_t* single_bal;
-
-        // Get the next reconcile state balance and merge with other balances
-        single_bal = load_single_acct_balances (sql_be, row);
-        if (single_bal != NULL)
-        {
-            if (bal != NULL && bal->acct != single_bal->acct)
-            {
-                bal->cleared_balance = gnc_numeric_add (bal->cleared_balance,
-                                                        bal->reconciled_balance,
-                                                        GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-                bal->balance = gnc_numeric_add (bal->balance, bal->cleared_balance,
-                                                GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-                bal_slist = g_slist_append (bal_slist, bal);
-                bal = NULL;
-            }
-            if (bal == NULL)
-            {
-                bal = g_malloc ((gsize)sizeof (acct_balances_t));
-                g_assert (bal != NULL);
-
-                bal->acct = single_bal->acct;
-                bal->balance = gnc_numeric_zero ();
-                bal->cleared_balance = gnc_numeric_zero ();
-                bal->reconciled_balance = gnc_numeric_zero ();
-            }
-            if (single_bal->reconcile_state == 'n')
-            {
-                bal->balance = gnc_numeric_add (bal->balance, single_bal->balance,
-                                                GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            }
-            else if (single_bal->reconcile_state == 'c')
-            {
-                bal->cleared_balance = gnc_numeric_add (bal->cleared_balance,
-                                                        single_bal->balance,
-                                                        GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            }
-            else if (single_bal->reconcile_state == 'y')
-            {
-                bal->reconciled_balance = gnc_numeric_add (bal->reconciled_balance,
-                                                           single_bal->balance,
-                                                           GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-            }
-            g_free (single_bal);
-        }
-    }
-
-    // Add the final balance
-    if (bal != NULL)
-    {
-        bal->cleared_balance = gnc_numeric_add (bal->cleared_balance,
-                                                bal->reconciled_balance,
-                                                GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-        bal->balance = gnc_numeric_add (bal->balance, bal->cleared_balance,
-                                        GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-        bal_slist = g_slist_append (bal_slist, bal);
-    }
-
-    return bal_slist;
-#else
-    return NULL;
-#endif
-}
-
 /* ----------------------------------------------------------------- */
 template<> void
 GncSqlColumnTableEntryImpl<CT_TXREF>::load (const GncSqlBackend* sql_be,
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.h b/libgnucash/backend/sql/gnc-transaction-sql.h
index f1b11cd..78d35b2 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.h
+++ b/libgnucash/backend/sql/gnc-transaction-sql.h
@@ -69,13 +69,5 @@ typedef struct
     gnc_numeric reconciled_balance;
 } acct_balances_t;
 
-/**
- * Returns a list of acct_balances_t structures, one for each account which
- * has splits.
- *
- * @param sql_be SQL backend
- * @return GSList of acct_balances_t structures
- */
-GSList* gnc_sql_get_account_balances_slist (GncSqlBackend* sql_be);
 
 #endif /* GNC_TRANSACTION_SQL_H */

commit e4d0ad9ddaecd18467433568b474f391d70496b9
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Mar 24 17:55:03 2018 -0700

    Reduce use of gnc_sql_slots_load_for_instancevec.

diff --git a/libgnucash/backend/sql/gnc-account-sql.cpp b/libgnucash/backend/sql/gnc-account-sql.cpp
index f0113ed..e926b0d 100644
--- a/libgnucash/backend/sql/gnc-account-sql.cpp
+++ b/libgnucash/backend/sql/gnc-account-sql.cpp
@@ -220,16 +220,14 @@ GncSqlAccountBackend::load_all (GncSqlBackend* sql_be)
 
     pBook = sql_be->book();
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
     for (auto row : *result)
         load_single_account (sql_be, row, l_accounts_needing_parents);
 
-    sql.str("");
-    sql << "SELECT DISTINCT guid FROM " << TABLE_NAME;
-    gnc_sql_slots_load_for_sql_subquery (sql_be, sql.str().c_str(),
+    sql = "SELECT DISTINCT guid FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
                                          (BookLookupFn)xaccAccountLookup);
 
     /* While there are items on the list of accounts needing parents,
diff --git a/libgnucash/backend/sql/gnc-bill-term-sql.cpp b/libgnucash/backend/sql/gnc-bill-term-sql.cpp
index ae813d8..31b4445 100644
--- a/libgnucash/backend/sql/gnc-bill-term-sql.cpp
+++ b/libgnucash/backend/sql/gnc-bill-term-sql.cpp
@@ -224,30 +224,35 @@ load_single_billterm (GncSqlBackend* sql_be, GncSqlRow& row,
     return pBillTerm;
 }
 
+/* Because gncBillTermLookup has the arguments backwards: */
+static inline GncBillTerm*
+gnc_billterm_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_BILLTERM, GncBillTerm);
+}
+
 void
 GncSqlBillTermBackend::load_all (GncSqlBackend* sql_be)
 {
 
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
     BillTermParentGuidVec l_billterms_needing_parents;
 
     for (auto row : *result)
     {
         auto pBillTerm =
             load_single_billterm (sql_be, row, l_billterms_needing_parents);
-        if (pBillTerm != nullptr)
-            instances.push_back(QOF_INSTANCE(pBillTerm));
     }
     delete result;
-
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_billterm_lookup);
 
     /* While there are items on the list of billterms needing parents,
        try to see if the parent has now been loaded.  Theory says that if
diff --git a/libgnucash/backend/sql/gnc-budget-sql.cpp b/libgnucash/backend/sql/gnc-budget-sql.cpp
index 9ad5fba..826e56d 100644
--- a/libgnucash/backend/sql/gnc-budget-sql.cpp
+++ b/libgnucash/backend/sql/gnc-budget-sql.cpp
@@ -327,22 +327,19 @@ load_single_budget (GncSqlBackend* sql_be, GncSqlRow& row)
 void
 GncSqlBudgetBackend::load_all (GncSqlBackend* sql_be)
 {
-    InstanceVec instances;
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << BUDGET_TABLE;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " BUDGET_TABLE);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
     for (auto row : *result)
-    {
         auto b = load_single_budget (sql_be, row);
-        if (b != nullptr)
-            instances.push_back(QOF_INSTANCE(b));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " BUDGET_TABLE;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_budget_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-commodity-sql.cpp b/libgnucash/backend/sql/gnc-commodity-sql.cpp
index 451b55a..32689d3 100644
--- a/libgnucash/backend/sql/gnc-commodity-sql.cpp
+++ b/libgnucash/backend/sql/gnc-commodity-sql.cpp
@@ -142,9 +142,8 @@ GncSqlCommodityBackend::load_all (GncSqlBackend* sql_be)
     gnc_commodity_table* pTable;
 
     pTable = gnc_commodity_table_get_table (sql_be->book());
-    std::stringstream sql;
-    sql << "SELECT * FROM " << COMMODITIES_TABLE;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " COMMODITIES_TABLE);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
 
     for (auto row : *result)
@@ -162,11 +161,12 @@ GncSqlCommodityBackend::load_all (GncSqlBackend* sql_be)
             qof_instance_set_guid (QOF_INSTANCE (pCommodity), &guid);
         }
 
-        auto sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", COMMODITIES_TABLE);
-        gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
-                                             (BookLookupFn)gnc_commodity_find_commodity_by_guid);
-        g_free (sql);
     }
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " COMMODITIES_TABLE;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_commodity_find_commodity_by_guid);
 }
 /* ================================================================= */
 static gboolean
diff --git a/libgnucash/backend/sql/gnc-customer-sql.cpp b/libgnucash/backend/sql/gnc-customer-sql.cpp
index de713eb..d4c2bfa 100644
--- a/libgnucash/backend/sql/gnc-customer-sql.cpp
+++ b/libgnucash/backend/sql/gnc-customer-sql.cpp
@@ -117,26 +117,30 @@ load_single_customer (GncSqlBackend* sql_be, GncSqlRow& row)
     return pCustomer;
 }
 
+/* Because gncCustomerLookup has the arguments backwards: */
+static inline GncCustomer*
+gnc_customer_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_CUSTOMER, GncCustomer);
+}
+
 void
 GncSqlCustomerBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncCustomer* pCustomer = load_single_customer (sql_be, row);
-        if (pCustomer != nullptr)
-            instances.push_back(QOF_INSTANCE(pCustomer));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_customer_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-employee-sql.cpp b/libgnucash/backend/sql/gnc-employee-sql.cpp
index 79c6346..afa0e90 100644
--- a/libgnucash/backend/sql/gnc-employee-sql.cpp
+++ b/libgnucash/backend/sql/gnc-employee-sql.cpp
@@ -101,30 +101,33 @@ load_single_employee (GncSqlBackend* sql_be, GncSqlRow& row)
 
     return pEmployee;
 }
+/* Because gncCustomerLookup has the arguments backwards: */
+static inline GncEmployee*
+gnc_employee_lookup (const GncGUID *guid, const QofBook *book)
+{
+    QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_EMPLOYEE, GncEmployee);
+}
 
 void
 GncSqlEmployeeBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
 
-    InstanceVec instances;
-
     for (auto row : *result)
-    {
         GncEmployee* pEmployee = load_single_employee (sql_be, row);
-        if (pEmployee != nullptr)
-            instances.push_back(QOF_INSTANCE(pEmployee));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_employee_lookup);
 }
 
+
 /* ================================================================= */
 void
 GncSqlEmployeeBackend::create_tables (GncSqlBackend* sql_be)
diff --git a/libgnucash/backend/sql/gnc-entry-sql.cpp b/libgnucash/backend/sql/gnc-entry-sql.cpp
index 764ffa4..f68e210 100644
--- a/libgnucash/backend/sql/gnc-entry-sql.cpp
+++ b/libgnucash/backend/sql/gnc-entry-sql.cpp
@@ -186,26 +186,30 @@ load_single_entry (GncSqlBackend* sql_be, GncSqlRow& row)
     return pEntry;
 }
 
+/* Because gncEntryLookup has the arguments backwards: */
+static inline GncEntry*
+gnc_entry_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_ENTRY, GncEntry);
+}
+
 void
 GncSqlEntryBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncEntry* pEntry = load_single_entry (sql_be, row);
-        if (pEntry != nullptr)
-            instances.push_back(QOF_INSTANCE(pEntry));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec(sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_entry_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-invoice-sql.cpp b/libgnucash/backend/sql/gnc-invoice-sql.cpp
index e0cc87a..29a18fd 100644
--- a/libgnucash/backend/sql/gnc-invoice-sql.cpp
+++ b/libgnucash/backend/sql/gnc-invoice-sql.cpp
@@ -124,26 +124,30 @@ load_single_invoice (GncSqlBackend* sql_be, GncSqlRow& row)
     return pInvoice;
 }
 
+/* Because gncInvoiceLookup has the arguments backwards: */
+static inline GncInvoice*
+gnc_invoice_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_INVOICE, GncInvoice);
+}
+
 void
 GncSqlInvoiceBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncInvoice* pInvoice = load_single_invoice (sql_be, row);
-        if (pInvoice != nullptr)
-            instances.push_back(QOF_INSTANCE(pInvoice));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_invoice_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-job-sql.cpp b/libgnucash/backend/sql/gnc-job-sql.cpp
index dd4d9f5..48e17aa 100644
--- a/libgnucash/backend/sql/gnc-job-sql.cpp
+++ b/libgnucash/backend/sql/gnc-job-sql.cpp
@@ -96,26 +96,30 @@ load_single_job (GncSqlBackend* sql_be, GncSqlRow& row)
     return pJob;
 }
 
+/* Because gncJobLookup has the arguments backwards: */
+static inline GncJob*
+gnc_job_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_JOB, GncJob);
+}
+
 void
 GncSqlJobBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncJob* pJob = load_single_job (sql_be, row);
-        if (pJob != nullptr)
-            instances.push_back(QOF_INSTANCE(pJob));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_job_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-order-sql.cpp b/libgnucash/backend/sql/gnc-order-sql.cpp
index b870a22..50cde38 100644
--- a/libgnucash/backend/sql/gnc-order-sql.cpp
+++ b/libgnucash/backend/sql/gnc-order-sql.cpp
@@ -98,26 +98,30 @@ load_single_order (GncSqlBackend* sql_be, GncSqlRow& row)
     return pOrder;
 }
 
+/* Because gncOrderLookup has the arguments backwards: */
+static inline GncOrder*
+gnc_order_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_ORDER, GncOrder);
+}
+
 void
 GncSqlOrderBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncOrder* pOrder = load_single_order (sql_be, row);
-        if (pOrder != nullptr)
-            instances.push_back(QOF_INSTANCE(pOrder));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_order_lookup);
 }
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-price-sql.cpp b/libgnucash/backend/sql/gnc-price-sql.cpp
index 85c440c..6a12872 100644
--- a/libgnucash/backend/sql/gnc-price-sql.cpp
+++ b/libgnucash/backend/sql/gnc-price-sql.cpp
@@ -102,9 +102,8 @@ GncSqlPriceBackend::load_all (GncSqlBackend* sql_be)
 
     pBook = sql_be->book();
     pPriceDB = gnc_pricedb_get_db (pBook);
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     if (stmt != nullptr)
     {
         auto result = sql_be->execute_select_statement(stmt);
@@ -112,7 +111,6 @@ GncSqlPriceBackend::load_all (GncSqlBackend* sql_be)
             return;
 
         GNCPrice* pPrice;
-        gchar* sql;
 
         gnc_pricedb_set_bulk_update (pPriceDB, TRUE);
         for (auto row : *result)
@@ -126,10 +124,11 @@ GncSqlPriceBackend::load_all (GncSqlBackend* sql_be)
             }
         }
         gnc_pricedb_set_bulk_update (pPriceDB, FALSE);
-
-        sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME);
-        gnc_sql_slots_load_for_sql_subquery (sql_be, sql, (BookLookupFn)gnc_price_lookup);
-        g_free (sql);
+	std::string pkey(col_table[0]->name());
+        sql = "SELECT DISTINCT ";
+	sql += pkey + " FROM " TABLE_NAME;
+        gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					     (BookLookupFn)gnc_price_lookup);
     }
 }
 
diff --git a/libgnucash/backend/sql/gnc-schedxaction-sql.cpp b/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
index f7909fd..c883a92 100644
--- a/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
@@ -115,18 +115,23 @@ load_single_sx (GncSqlBackend* sql_be, GncSqlRow& row)
     return pSx;
 }
 
+/* Because SchedXaction doesn't define a lookup function: */
+static inline SchedXaction*
+gnc_sx_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_SCHEDXACTION, SchedXaction);
+}
+
 void
 GncSqlSchedXactionBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << SCHEDXACTION_TABLE;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
-    if (stmt == NULL) return;
+    std::string sql("SELECT * FROM " SCHEDXACTION_TABLE);
+    auto stmt = sql_be->create_statement_from_sql(sql);
+    if (stmt == nullptr) return;
     auto result = sql_be->execute_select_statement(stmt);
     SchedXactions* sxes;
-    InstanceVec instances;
     sxes = gnc_book_get_schedxactions (sql_be->book());
 
     for (auto row : *result)
@@ -135,14 +140,13 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* sql_be)
 
         sx = load_single_sx (sql_be, row);
         if (sx != nullptr)
-        {
             gnc_sxes_add_sx (sxes, sx);
-            instances.push_back(QOF_INSTANCE(sx));
-        }
     }
-
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " SCHEDXACTION_TABLE;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_sx_lookup);
 }
 
 
diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index ca26617..ab2d6e4 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -766,19 +766,15 @@ gnc_sql_slots_load (GncSqlBackend* sql_be, QofInstance* inst)
 static void
 slots_load_info (slot_info_t* pInfo)
 {
-    gchar guid_buf[GUID_ENCODING_LENGTH + 1];
-
     g_return_if_fail (pInfo != NULL);
     g_return_if_fail (pInfo->be != NULL);
     g_return_if_fail (pInfo->guid != NULL);
     g_return_if_fail (pInfo->pKvpFrame != NULL);
 
-    (void)guid_to_string_buff (pInfo->guid, guid_buf);
-
-    std::stringstream buf;
-    buf << "SELECT * FROM " << TABLE_NAME <<
-        " WHERE obj_guid='" << guid_buf << "'";
-    auto stmt = pInfo->be->create_statement_from_sql (buf.str());
+    gnc::GUID guid(*pInfo->guid);
+    std::string sql("SELECT * FROM " TABLE_NAME " WHERE obj_guid='");
+    sql += guid.to_string() + "'";
+    auto stmt = pInfo->be->create_statement_from_sql(sql);
     if (stmt != nullptr)
     {
         auto result = pInfo->be->execute_select_statement (stmt);
@@ -897,29 +893,25 @@ load_slot_for_book_object (GncSqlBackend* sql_be, GncSqlRow& row,
  * @param lookup_fn Lookup function
  */
 void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* sql_be,
-                                          const gchar* subquery,
+                                          const std::string subquery,
                                           BookLookupFn lookup_fn)
 {
-    gchar* sql;
-
     g_return_if_fail (sql_be != NULL);
 
     // Ignore empty subquery
-    if (subquery == NULL) return;
+    if (subquery.empty()) return;
 
-    sql = g_strdup_printf ("SELECT * FROM %s WHERE %s IN (%s)",
-                           TABLE_NAME, obj_guid_col_table[0]->name(),
-                           subquery);
+    std::string pkey(obj_guid_col_table[0]->name());
+    std::string sql("SELECT * FROM " TABLE_NAME " WHERE ");
+    sql += pkey + " IN (" + subquery + ")";
 
     // Execute the query and load the slots
     auto stmt = sql_be->create_statement_from_sql(sql);
     if (stmt == nullptr)
     {
-        PERR ("stmt == NULL, SQL = '%s'\n", sql);
-        g_free (sql);
+        PERR ("stmt == NULL, SQL = '%s'\n", sql.c_str());
         return;
     }
-    g_free (sql);
     auto result = sql_be->execute_select_statement(stmt);
     for (auto row : *result)
         load_slot_for_book_object (sql_be, row, lookup_fn);
diff --git a/libgnucash/backend/sql/gnc-slots-sql.h b/libgnucash/backend/sql/gnc-slots-sql.h
index 56ef2e5..0cdf3a6 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.h
+++ b/libgnucash/backend/sql/gnc-slots-sql.h
@@ -100,7 +100,7 @@ typedef QofInstance* (*BookLookupFn) (const GncGUID* guid,
  * @param lookup_fn Lookup function to get the right object from the book
  */
 void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* sql_be,
-                                          const gchar* subquery,
+                                          const std::string subquery,
                                           BookLookupFn lookup_fn);
 
 void gnc_sql_init_slots_handler (void);
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index c8ddd1e..8f92178 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -264,17 +264,13 @@ load_splits_for_tx_list (GncSqlBackend* sql_be, InstanceVec& transactions)
     // Execute the query and load the splits
     auto stmt = sql_be->create_statement_from_sql(sql.str());
     auto result = sql_be->execute_select_statement (stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         Split* s = load_single_split (sql_be, row);
-        if (s != nullptr)
-            instances.push_back(QOF_INSTANCE(s));
-    }
-
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    sql = "SELECT DISTINCT ";
+    sql += spkey + " FROM " SPLIT_TABLE " WHERE " + sskey + " IN " + selector;
+    gnc_sql_slots_load_for_sql_subquery(sql_be, sql,
+					(BookLookupFn)xaccSplitLookup);
 }
 
 static  Transaction*
diff --git a/libgnucash/backend/sql/gnc-vendor-sql.cpp b/libgnucash/backend/sql/gnc-vendor-sql.cpp
index ae60b3a..a73c29c 100644
--- a/libgnucash/backend/sql/gnc-vendor-sql.cpp
+++ b/libgnucash/backend/sql/gnc-vendor-sql.cpp
@@ -106,26 +106,30 @@ load_single_vendor (GncSqlBackend* sql_be, GncSqlRow& row)
     return pVendor;
 }
 
+/* Because gncVendorLookup has the arguments backwards: */
+static inline GncVendor*
+gnc_vendor_lookup (const GncGUID *guid, const QofBook *book)
+{
+     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_VENDOR, GncVendor);
+}
+
 void
 GncSqlVendorBackend::load_all (GncSqlBackend* sql_be)
 {
     g_return_if_fail (sql_be != NULL);
 
-    std::stringstream sql;
-    sql << "SELECT * FROM " << TABLE_NAME;
-    auto stmt = sql_be->create_statement_from_sql(sql.str());
+    std::string sql("SELECT * FROM " TABLE_NAME);
+    auto stmt = sql_be->create_statement_from_sql(sql);
     auto result = sql_be->execute_select_statement(stmt);
-    InstanceVec instances;
 
     for (auto row : *result)
-    {
         GncVendor* pVendor = load_single_vendor (sql_be, row);
-        if (pVendor != nullptr)
-            instances.push_back(QOF_INSTANCE(pVendor));
-    }
 
-    if (!instances.empty())
-        gnc_sql_slots_load_for_instancevec (sql_be, instances);
+    std::string pkey(col_table[0]->name());
+    sql = "SELECT DISTINCT ";
+    sql += pkey + " FROM " TABLE_NAME;
+    gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
+					 (BookLookupFn)gnc_vendor_lookup);
 }
 
 /* ================================================================= */



Summary of changes:
 libgnucash/app-utils/gnc-ui-util.c              |   4 +-
 libgnucash/backend/sql/gnc-account-sql.cpp      |  31 +-
 libgnucash/backend/sql/gnc-bill-term-sql.cpp    |  23 +-
 libgnucash/backend/sql/gnc-budget-sql.cpp       |  17 +-
 libgnucash/backend/sql/gnc-commodity-sql.cpp    |  14 +-
 libgnucash/backend/sql/gnc-customer-sql.cpp     |  24 +-
 libgnucash/backend/sql/gnc-employee-sql.cpp     |  25 +-
 libgnucash/backend/sql/gnc-entry-sql.cpp        |  24 +-
 libgnucash/backend/sql/gnc-invoice-sql.cpp      |  24 +-
 libgnucash/backend/sql/gnc-job-sql.cpp          |  24 +-
 libgnucash/backend/sql/gnc-order-sql.cpp        |  24 +-
 libgnucash/backend/sql/gnc-price-sql.cpp        |  15 +-
 libgnucash/backend/sql/gnc-schedxaction-sql.cpp |  26 +-
 libgnucash/backend/sql/gnc-slots-sql.cpp        |  66 +---
 libgnucash/backend/sql/gnc-slots-sql.h          |  13 +-
 libgnucash/backend/sql/gnc-sql-backend.cpp      |  12 +-
 libgnucash/backend/sql/gnc-transaction-sql.cpp  | 468 +++---------------------
 libgnucash/backend/sql/gnc-transaction-sql.h    |   8 -
 libgnucash/backend/sql/gnc-vendor-sql.cpp       |  24 +-
 libgnucash/core-utils/gnc-guile-utils.c         |   2 +-
 libgnucash/engine/TransLog.c                    |   2 +-
 21 files changed, 229 insertions(+), 641 deletions(-)



More information about the gnucash-changes mailing list