gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Fri May 8 19:05:26 EDT 2020


Updated	 via  https://github.com/Gnucash/gnucash/commit/4e6c497c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/320db327 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8ff5af4c (commit)
	from  https://github.com/Gnucash/gnucash/commit/0a4347bd (commit)



commit 4e6c497cd17d233731e2b885f107cf54411f9e7c
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri May 8 15:47:30 2020 -0700

    Don't ask to save a non-existant book.
    
    To accomplish that we separate creating a book and creating a session;
    gnc_get_session no longer automatically creates a book if one isn't
    connected.
    
    We also add an initially_insensitive GtkAction array to
    gnc-plugin-basic-commands with a call to make its contents insensitive
    at plugin load so that the save button on the toolbar isn't lighted when
    there's nothing to save.

diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 1b8f70145..5b1d67c20 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -651,7 +651,7 @@ gnc_file_query_save (GtkWindow *parent, gboolean can_cancel)
 static gboolean
 gnc_post_file_open (GtkWindow *parent, const char * filename, gboolean is_readonly)
 {
-    QofSession *current_session, *new_session;
+    QofSession *new_session;
     QofBook *new_book;
     GList *invalid_account_names;
     gboolean uh_oh = FALSE;
@@ -726,7 +726,7 @@ RESTART:
     /* -- this code is almost identical in FileOpen and FileSaveAs -- */
     if (gnc_current_session_exist())
     {
-        current_session = gnc_get_current_session();
+        QofSession *current_session = gnc_get_current_session();
         gnc_hook_run(HOOK_BOOK_CLOSED, current_session);
         gnc_close_gui_component_by_session (current_session);
         gnc_state_save (current_session);
@@ -735,7 +735,7 @@ RESTART:
 
     /* load the accounts from the users datafile */
     /* but first, check to make sure we've got a session going. */
-    new_session = qof_session_new (NULL);
+    new_session = qof_session_new (qof_book_new());
 
     // Begin the new session. If we are in read-only mode, ignore the locks.
     qof_session_begin (new_session, newfile, is_readonly, FALSE, FALSE);
@@ -1299,6 +1299,9 @@ gnc_file_save (GtkWindow *parent)
     QofSession *session;
     ENTER (" ");
 
+    if (!gnc_current_session_exist ())
+        return; //No session means nothing to save.
+
     /* hack alert -- Somehow make sure all in-progress edits get committed! */
 
     /* If we don't have a filename/path to save to get one. */
@@ -1366,6 +1369,12 @@ gnc_file_save_as (GtkWindow *parent)
 
     ENTER(" ");
 
+    if (!gnc_current_session_exist ())
+    {
+        LEAVE("No Session.");
+        return;
+    }
+
     last = gnc_history_get_last();
     if ( last && gnc_uri_targets_local_fs (last))
     {
diff --git a/gnucash/gnome/gnc-plugin-basic-commands.c b/gnucash/gnome/gnc-plugin-basic-commands.c
index 51de83442..4deddcfe7 100644
--- a/gnucash/gnome/gnc-plugin-basic-commands.c
+++ b/gnucash/gnome/gnc-plugin-basic-commands.c
@@ -239,6 +239,14 @@ static const gchar *gnc_plugin_important_actions[] =
     NULL,
 };
 
+/** The following items should be made insensitive at startup time.  The
+ *  sensitivity will be changed by some later event. */
+static const gchar *gnc_plugin_initially_insensitive_actions[] =
+{
+    "FileSaveAction",
+    NULL,
+};
+
 /** These actions are made not sensitive (i.e.,
  * their toolbar and menu items are grayed out and do not send events
  * when clicked) when the current book is "Read Only".
@@ -309,6 +317,11 @@ gnc_plugin_basic_commands_add_to_window (GncPlugin *plugin,
         GncMainWindow *window,
         GQuark type)
 {
+    GtkActionGroup *action_group =
+        gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME);
+    gnc_plugin_update_actions(action_group,
+                              gnc_plugin_initially_insensitive_actions,
+                              "sensitive", FALSE);
     g_signal_connect(window, "page_changed",
                      G_CALLBACK(gnc_plugin_basic_commands_main_window_page_changed),
                      plugin);
diff --git a/gnucash/import-export/aqb/test/test-kvp.c b/gnucash/import-export/aqb/test/test-kvp.c
index 4e13cebd8..62458e08b 100644
--- a/gnucash/import-export/aqb/test/test-kvp.c
+++ b/gnucash/import-export/aqb/test/test-kvp.c
@@ -64,7 +64,8 @@ test_qofsession_aqb_kvp( void )
     if (1)
     {
         // A file with no content at all, but a valid XML file
-        QofSession *new_session = qof_session_new (NULL);
+        QofBook *book = qof_book_new();
+        QofSession *new_session = qof_session_new (book);
         char *newfile = g_strdup_printf("file://%s", file1);
 
         qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);
@@ -92,7 +93,8 @@ test_qofsession_aqb_kvp( void )
     {
         // A file with no content except for the book_template_list kvp
         // slot
-        QofSession *new_session = qof_session_new (NULL);
+        QofBook *book = qof_book_new();
+        QofSession *new_session = qof_session_new (book);
         char *newfile = g_strdup_printf("file://%s", file2);
 
         qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);
diff --git a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
index c824959b3..994c5e8c4 100644
--- a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
+++ b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
@@ -91,7 +91,8 @@ setup (Fixture* fixture, gconstpointer pData)
 {
     gchar* url = (gchar*)pData;
     gnc_module_init_backend_dbi();
-    fixture->session = qof_session_new (nullptr);
+    auto book = qof_book_new();
+    fixture->session = qof_session_new (book);
     /* When running distcheck the source directory is read-only, which
      * prevents creating the lock file. Force the session to get
      * around that.
@@ -391,7 +392,8 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
         url = fixture->filename;
 
     // Save the session data
-    auto session_2 = qof_session_new (nullptr);
+    auto book2{qof_book_new()};
+    auto session_2 = qof_session_new (book2);
     qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
     g_assert (session_2 != NULL);
     g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
@@ -402,7 +404,8 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
     g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
 
     // Reload the session data
-    auto session_3 = qof_session_new (nullptr);
+    auto book3{qof_book_new()};
+    auto session_3 = qof_session_new (book3);
     g_assert (session_3 != NULL);
     qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
     g_assert (session_3 != NULL);
@@ -442,7 +445,8 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
         url = fixture->filename;
 
     // Load the session data
-    auto session_1 = qof_session_new (nullptr);
+    auto book1{qof_book_new()};
+    auto session_1 = qof_session_new (book1);
     qof_session_begin (session_1, url, FALSE, TRUE, TRUE);
     if (session_1 &&
         qof_session_get_error (session_1) != ERR_BACKEND_NO_ERR)
@@ -468,7 +472,7 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
     }
     /* Destroy the session and reload it */
 
-    session_2 = qof_session_new (nullptr);
+    session_2 = qof_session_new (qof_book_new());
     qof_session_begin (session_2, url, TRUE, FALSE, FALSE);
     if (session_2 &&
         qof_session_get_error (session_2) != ERR_BACKEND_NO_ERR)
@@ -508,7 +512,7 @@ static void
 test_dbi_version_control (Fixture* fixture, gconstpointer pData)
 {
     auto url = (gchar*)pData;
-    QofBook* book = nullptr;
+    QofBook* book{qof_book_new()};
     QofBackendError err;
     gint ourversion = gnc_prefs_get_long_version ();
     GncSqlBackend* sql_be = nullptr;
@@ -536,7 +540,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
     qof_book_commit_edit (book);
     qof_session_end (sess);
     qof_session_destroy (sess);
-    sess = qof_session_new (nullptr);
+    sess = qof_session_new (qof_book_new());
     qof_session_begin (sess, url, TRUE, FALSE, FALSE);
     qof_session_load (sess, NULL);
     err = qof_session_pop_error (sess);
@@ -549,7 +553,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
     qof_book_commit_edit (book);
     qof_session_end (sess);
     qof_session_destroy (sess);
-    sess = qof_session_new (nullptr);
+    sess = qof_session_new (qof_book_new());
     qof_session_begin (sess, url, TRUE, FALSE, FALSE);
     qof_session_load (sess, NULL);
     qof_session_ensure_all_data_loaded (sess);
@@ -578,14 +582,14 @@ test_dbi_business_store_and_reload (Fixture* fixture, gconstpointer pData)
     if (fixture->filename)
         url = fixture->filename;
     // Save the session data
-    auto session_2 = qof_session_new (nullptr);
+    auto session_2 = qof_session_new (qof_book_new());
     qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
     qof_session_swap_data (fixture->session, session_2);
     qof_book_mark_session_dirty (qof_session_get_book (session_2));
     qof_session_save (session_2, NULL);
 
     // Reload the session data
-    auto session_3 = qof_session_new (nullptr);
+    auto session_3 = qof_session_new (qof_book_new());
     qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
     qof_session_load (session_3, NULL);
 
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index a6ede7ac5..ed995fc35 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -1152,7 +1152,7 @@ gnc_book_get_root_account (QofBook *book)
     if (!book) return NULL;
     col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
     root = gnc_coll_get_root_account (col);
-    if (root == NULL)
+    if (root == NULL && !qof_book_shutting_down(book))
         root = gnc_account_create_root(book);
     return root;
 }
@@ -5875,6 +5875,8 @@ static void
 gnc_account_book_end(QofBook* book)
 {
     Account *root_account = gnc_book_get_root_account(book);
+    if (!root_account)
+        return;
     xaccAccountBeginEdit(root_account);
     xaccAccountDestroy(root_account);
 }
diff --git a/libgnucash/engine/qofsession.cpp b/libgnucash/engine/qofsession.cpp
index 1db4b6b54..03a9c3001 100644
--- a/libgnucash/engine/qofsession.cpp
+++ b/libgnucash/engine/qofsession.cpp
@@ -202,52 +202,49 @@ QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
 {
     /* We must have an empty book to load into or bad things will happen. */
     g_return_if_fail(m_book && qof_book_empty(m_book));
-    
+
     if (!m_book_id.size ()) return;
     ENTER ("sess=%p book_id=%s", this, m_book_id.c_str ());
 
     /* At this point, we should are supposed to have a valid book
-    * id and a lock on the file. */
+     * id and a lock on the file. */
     clear_error ();
 
     /* This code should be sufficient to initialize *any* backend,
-    * whether http, postgres, or anything else that might come along.
-    * Basically, the idea is that by now, a backend has already been
-    * created & set up.  At this point, we only need to get the
-    * top-level account group out of the backend, and that is a
-    * generic, backend-independent operation.
-    */
-    qof_book_set_backend (newbook, m_backend);
+     * whether http, postgres, or anything else that might come along.
+     * Basically, the idea is that by now, a backend has already been
+     * created & set up.  At this point, we only need to get the
+     * top-level account group out of the backend, and that is a
+     * generic, backend-independent operation.
+     */
+    qof_book_set_backend (m_book, m_backend);
 
     /* Starting the session should result in a bunch of accounts
-    * and currencies being downloaded, but probably no transactions;
-    * The GUI will need to do a query for that.
-    */
+     * and currencies being downloaded, but probably no transactions;
+     * The GUI will need to do a query for that.
+     */
     if (m_backend)
     {
         m_backend->set_percentage(percentage_func);
-        m_backend->load (newbook, LOAD_TYPE_INITIAL_LOAD);
+        m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
         push_error (m_backend->get_error(), {});
     }
 
     auto err = get_error ();
     if ((err != ERR_BACKEND_NO_ERR) &&
-            (err != ERR_FILEIO_FILE_TOO_OLD) &&
-            (err != ERR_FILEIO_NO_ENCODING) &&
-            (err != ERR_FILEIO_FILE_UPGRADE) &&
-            (err != ERR_SQL_DB_TOO_OLD) &&
-            (err != ERR_SQL_DB_TOO_NEW))
+        (err != ERR_FILEIO_FILE_TOO_OLD) &&
+        (err != ERR_FILEIO_NO_ENCODING) &&
+        (err != ERR_FILEIO_FILE_UPGRADE) &&
+        (err != ERR_SQL_DB_TOO_OLD) &&
+        (err != ERR_SQL_DB_TOO_NEW))
     {
-        /* Something broke, put back the old stuff */
-        delete m_backend;
-        qof_book_set_backend (newbook, NULL);
-        qof_book_destroy (newbook);
-        m_book = oldbook;
-        m_backend = qof_book_get_backend (m_book);
+        // Something failed, delete and restore new ones.
+        destroy_backend();
+        qof_book_destroy (m_book);
+        m_book = qof_book_new();
         LEAVE ("error from backend %d", get_error ());
         return;
     }
-    qof_book_destroy (oldbook);
 
     LEAVE ("sess = %p, book_id=%s", this, m_book_id.c_str ());
 }
diff --git a/libgnucash/engine/test/test-qofsession.cpp b/libgnucash/engine/test/test-qofsession.cpp
index ae9b57311..0179f830d 100644
--- a/libgnucash/engine/test/test-qofsession.cpp
+++ b/libgnucash/engine/test/test-qofsession.cpp
@@ -175,19 +175,25 @@ TEST (QofSessionTest, load)
      * and create a new one.
      */
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s{qof_book_new()};
     s.begin ("book1", false, false, false);
-    auto book = s.get_book ();
+    char *guidstr1 = guid_to_string(qof_instance_get_guid(s.get_book ()));
     s.load (nullptr);
-    EXPECT_NE (book, s.get_book ());
+    char *guidstr2 = guid_to_string(qof_instance_get_guid(s.get_book ()));
+    EXPECT_STRNE (guidstr1, guidstr2);
+    g_free(guidstr1);
+    g_free(guidstr2);
 
     /* Now we'll do the load without returning an error from the backend,
      * and ensure that it's the new book from the previous test.
      */
     load_error = false;
-    book = s.get_book();
+    guidstr1 = guid_to_string(qof_instance_get_guid(s.get_book ()));
     s.load (nullptr);
-    EXPECT_EQ (book, s.get_book ());
+    guidstr2 = guid_to_string(qof_instance_get_guid(s.get_book ()));
+    EXPECT_STREQ (guidstr1, guidstr2);
+    g_free(guidstr1);
+    g_free(guidstr2);
     EXPECT_EQ (s.get_error(), ERR_BACKEND_NO_ERR);
     //But it's still empty, to the book shouldn't need saving
     EXPECT_FALSE(qof_book_session_not_saved (s.get_book ()));

commit 320db3270bb1b87f816047ec9cf7573aa370207c
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri May 8 15:29:24 2020 -0700

    Remove duplicate decl.

diff --git a/bindings/python/sqlite3test.c b/bindings/python/sqlite3test.c
index 29bce37e1..a1e626952 100644
--- a/bindings/python/sqlite3test.c
+++ b/bindings/python/sqlite3test.c
@@ -26,10 +26,9 @@ int main()
     const char* testurl = "sqlite3://" TESTFILE;
     char * no_args[1] = { NULL };
     QofSession* s = NULL;
-    
+
     qof_log_init();
     qof_init();
-    char * no_args[1] = { NULL };
     gnc_engine_init(0, no_args);
 
     s = qof_session_new(NULL);

commit 8ff5af4c19838825c9bff2c5856e05cba53b910e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jun 17 16:43:33 2018 -0700

    Decouple QofBook creation from QofSession.
    
    So that we don't create two books when loading a session.
    Step 1 to not having a dirty book when we think we should have no
    book at all.

diff --git a/bindings/engine.i b/bindings/engine.i
index c6af91a1e..5ff358ac7 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -181,7 +181,7 @@ functions. */
 %include <policy.h>
 %include <gnc-pricedb.h>
 
-QofSession * qof_session_new (void);
+QofSession * qof_session_new (QofBook* book);
 QofBook * qof_session_get_book (QofSession *session);
 // TODO: Unroll/remove
 const char *qof_session_get_url (QofSession *session);
@@ -271,6 +271,7 @@ Account * gnc_book_get_template_root(QofBook *book);
 %typemap(out) KvpValue * " $result = gnc_kvp_value_ptr_to_scm($1); "
 %typemap(in) GSList *key_path " $1 = gnc_scm_to_gslist_string($input);"
 
+QofBook* qof_book_new (void);
 void qof_book_options_delete (QofBook *book, GSList *key_path);
 void qof_book_set_option (QofBook *book, KvpValue *new_value, GSList *key_path);
 KvpValue* qof_book_get_option (QofBook *book, GSList *key_path);
diff --git a/bindings/guile/test/test-create-account.scm b/bindings/guile/test/test-create-account.scm
index b97228981..4e3fcc066 100644
--- a/bindings/guile/test/test-create-account.scm
+++ b/bindings/guile/test/test-create-account.scm
@@ -25,8 +25,7 @@
 (define (run-test)
   (setenv "GNC_UNINSTALLED" "1")
 
-  (let* ((session (qof-session-new))
-         (book (qof-session-get-book session))
+  (let* ((book (qof-book-new))
          (root (xaccMallocAccount book))
          (acct (xaccMallocAccount book)))
     (xaccAccountBeginEdit acct)
diff --git a/bindings/python/gnucash_core.i b/bindings/python/gnucash_core.i
index bbaf15d1f..393efa5a6 100644
--- a/bindings/python/gnucash_core.i
+++ b/bindings/python/gnucash_core.i
@@ -224,4 +224,5 @@ char * no_args[1] = { NULL };
 gnc_engine_init(0, no_args);
 gnc_prefs_init();
 %}
-
+//We must explicitly declare this or it gets left out and we can't create books.
+QofBook* qof_book_new (void);
diff --git a/bindings/python/gnucash_core.py b/bindings/python/gnucash_core.py
index c68ecd737..6302fba46 100644
--- a/bindings/python/gnucash_core.py
+++ b/bindings/python/gnucash_core.py
@@ -103,7 +103,7 @@ class Session(GnuCashCoreClass):
         you don't need to cleanup and call end() and destroy(), that is handled
         for you, and the exception is raised.
         """
-        GnuCashCoreClass.__init__(self, instance=instance)
+        GnuCashCoreClass.__init__(self, Book())
         if book_uri is not None:
             try:
                 self.begin(book_uri, ignore_lock, is_new, force_new)
diff --git a/bindings/python/sqlite3test.c b/bindings/python/sqlite3test.c
index 40b2720fe..29bce37e1 100644
--- a/bindings/python/sqlite3test.c
+++ b/bindings/python/sqlite3test.c
@@ -24,12 +24,15 @@
 int main()
 {
     const char* testurl = "sqlite3://" TESTFILE;
+    char * no_args[1] = { NULL };
+    QofSession* s = NULL;
+    
     qof_log_init();
     qof_init();
     char * no_args[1] = { NULL };
     gnc_engine_init(0, no_args);
 
-    QofSession * s = qof_session_new();
+    s = qof_session_new(NULL);
     qof_session_begin(s, testurl, 0, 1, 0);
     qof_session_load(s, NULL);
     qof_session_save(s, NULL);
diff --git a/gnucash/gnome-utils/assistant-xml-encoding.c b/gnucash/gnome-utils/assistant-xml-encoding.c
index 83b93b072..d70222670 100644
--- a/gnucash/gnome-utils/assistant-xml-encoding.c
+++ b/gnucash/gnome-utils/assistant-xml-encoding.c
@@ -1080,7 +1080,7 @@ gxi_parse_file (GncXmlImportData *data)
 
     /* create a temporary QofSession */
     gxi_session_destroy (data);
-    session = qof_session_new ();
+    session = qof_session_new (NULL);
     data->session = session;
     qof_session_begin (session, data->filename, TRUE, FALSE, FALSE);
     io_err = qof_session_get_error (session);
diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 555cf2d2f..1b8f70145 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -735,7 +735,7 @@ RESTART:
 
     /* load the accounts from the users datafile */
     /* but first, check to make sure we've got a session going. */
-    new_session = qof_session_new ();
+    new_session = qof_session_new (NULL);
 
     // Begin the new session. If we are in read-only mode, ignore the locks.
     qof_session_begin (new_session, newfile, is_readonly, FALSE, FALSE);
@@ -752,6 +752,8 @@ RESTART:
 
         filename = gnc_file_dialog (parent, NULL, NULL, directory,
                                     GNC_FILE_DIALOG_OPEN);
+        /* Suppress trying to save the empty session. */
+        qof_book_mark_session_saved (qof_session_get_book (new_session));
         qof_session_destroy (new_session);
         new_session = NULL;
         g_free (directory);
@@ -1231,7 +1233,7 @@ gnc_file_do_export(GtkWindow *parent, const char * filename)
 
     /* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
 
-    new_session = qof_session_new ();
+    new_session = qof_session_new (NULL);
     qof_session_begin (new_session, newfile, FALSE, TRUE, FALSE);
 
     io_err = qof_session_get_error (new_session);
@@ -1468,7 +1470,7 @@ gnc_file_do_save_as (GtkWindow *parent, const char* filename)
 
     save_in_progress++;
 
-    new_session = qof_session_new ();
+    new_session = qof_session_new (NULL);
     qof_session_begin (new_session, newfile, FALSE, TRUE, FALSE);
 
     io_err = qof_session_get_error (new_session);
diff --git a/gnucash/import-export/aqb/test/test-kvp.c b/gnucash/import-export/aqb/test/test-kvp.c
index 29e7f8545..4e13cebd8 100644
--- a/gnucash/import-export/aqb/test/test-kvp.c
+++ b/gnucash/import-export/aqb/test/test-kvp.c
@@ -64,7 +64,7 @@ test_qofsession_aqb_kvp( void )
     if (1)
     {
         // A file with no content at all, but a valid XML file
-        QofSession *new_session = qof_session_new ();
+        QofSession *new_session = qof_session_new (NULL);
         char *newfile = g_strdup_printf("file://%s", file1);
 
         qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);
@@ -92,7 +92,7 @@ test_qofsession_aqb_kvp( void )
     {
         // A file with no content except for the book_template_list kvp
         // slot
-        QofSession *new_session = qof_session_new ();
+        QofSession *new_session = qof_session_new (NULL);
         char *newfile = g_strdup_printf("file://%s", file2);
 
         qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE);
diff --git a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
index 4980adb76..c824959b3 100644
--- a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
+++ b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
@@ -91,7 +91,7 @@ setup (Fixture* fixture, gconstpointer pData)
 {
     gchar* url = (gchar*)pData;
     gnc_module_init_backend_dbi();
-    fixture->session = qof_session_new ();
+    fixture->session = qof_session_new (nullptr);
     /* When running distcheck the source directory is read-only, which
      * prevents creating the lock file. Force the session to get
      * around that.
@@ -111,9 +111,9 @@ setup (Fixture* fixture, gconstpointer pData)
 static void
 setup_memory (Fixture* fixture, gconstpointer pData)
 {
-    QofSession* session = nullptr;
     gchar* url = (gchar*)pData;
-    QofBook* book;
+    auto book = qof_book_new();
+    auto session = qof_session_new (book);
     Account* root, *acct1, *acct2;
     Transaction* tx;
     Split* spl1, *spl2;
@@ -121,8 +121,6 @@ setup_memory (Fixture* fixture, gconstpointer pData)
     gnc_commodity* currency;
 
     gnc_module_init_backend_dbi();
-    session = qof_session_new ();
-    book = qof_session_get_book (session);
     root = gnc_book_get_root_account (book);
 
     table = gnc_commodity_table_get_table (book);
@@ -170,9 +168,9 @@ static void
 setup_business (Fixture* fixture, gconstpointer pData)
 {
     gnc_module_init_backend_dbi ();
-    QofSession* session = qof_session_new ();
+    auto book = qof_book_new ();
+    auto session = qof_session_new (book);
     gchar* url = (gchar*)pData;
-    QofBook* book = qof_session_get_book (session);
     Account* root = gnc_book_get_root_account (book);
     Account* acct1;
     Account* acct2;
@@ -382,9 +380,6 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
 {
 
     const gchar* url = (const gchar*)pData;
-    QofSession* session_2;
-    QofSession* session_3;
-
     auto msg = "[GncDbiSqlConnection::unlock_database()] There was no lock entry in the Lock table";
     auto log_domain = nullptr;
     auto loglevel = static_cast<GLogLevelFlags> (G_LOG_LEVEL_WARNING |
@@ -396,7 +391,7 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
         url = fixture->filename;
 
     // Save the session data
-    session_2 = qof_session_new ();
+    auto session_2 = qof_session_new (nullptr);
     qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
     g_assert (session_2 != NULL);
     g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
@@ -407,7 +402,7 @@ test_dbi_store_and_reload (Fixture* fixture, gconstpointer pData)
     g_assert_cmpint (qof_session_get_error (session_2), == , ERR_BACKEND_NO_ERR);
 
     // Reload the session data
-    session_3 = qof_session_new ();
+    auto session_3 = qof_session_new (nullptr);
     g_assert (session_3 != NULL);
     qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
     g_assert (session_3 != NULL);
@@ -436,8 +431,7 @@ static void
 test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
 {
     auto url = (gchar*)pData;
-    QofSession* session_1 = NULL, *session_2 = NULL;
-
+    QofSession* session_2 = nullptr; // Otherwise goto cleanup bypasses init.
     auto msg = "[GncDbiSqlConnection::unlock_database()] There was no lock entry in the Lock table";
     auto log_domain = nullptr;
     auto loglevel = static_cast<GLogLevelFlags> (G_LOG_LEVEL_WARNING |
@@ -448,7 +442,7 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
         url = fixture->filename;
 
     // Load the session data
-    session_1 = qof_session_new ();
+    auto session_1 = qof_session_new (nullptr);
     qof_session_begin (session_1, url, FALSE, TRUE, TRUE);
     if (session_1 &&
         qof_session_get_error (session_1) != ERR_BACKEND_NO_ERR)
@@ -474,7 +468,7 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData)
     }
     /* Destroy the session and reload it */
 
-    session_2 = qof_session_new ();
+    session_2 = qof_session_new (nullptr);
     qof_session_begin (session_2, url, TRUE, FALSE, FALSE);
     if (session_2 &&
         qof_session_get_error (session_2) != ERR_BACKEND_NO_ERR)
@@ -514,8 +508,7 @@ static void
 test_dbi_version_control (Fixture* fixture, gconstpointer pData)
 {
     auto url = (gchar*)pData;
-    QofSession* sess;
-    QofBook* book;
+    QofBook* book = nullptr;
     QofBackendError err;
     gint ourversion = gnc_prefs_get_long_version ();
     GncSqlBackend* sql_be = nullptr;
@@ -523,7 +516,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
     // Load the session data
     if (fixture->filename)
         url = fixture->filename;
-    sess = qof_session_new ();
+    auto sess = qof_session_new (nullptr);
     qof_session_begin (sess, url, FALSE, TRUE, TRUE);
     if (sess && qof_session_get_error (sess) != ERR_BACKEND_NO_ERR)
     {
@@ -543,7 +536,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
     qof_book_commit_edit (book);
     qof_session_end (sess);
     qof_session_destroy (sess);
-    sess = qof_session_new ();
+    sess = qof_session_new (nullptr);
     qof_session_begin (sess, url, TRUE, FALSE, FALSE);
     qof_session_load (sess, NULL);
     err = qof_session_pop_error (sess);
@@ -556,7 +549,7 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData)
     qof_book_commit_edit (book);
     qof_session_end (sess);
     qof_session_destroy (sess);
-    sess = qof_session_new ();
+    sess = qof_session_new (nullptr);
     qof_session_begin (sess, url, TRUE, FALSE, FALSE);
     qof_session_load (sess, NULL);
     qof_session_ensure_all_data_loaded (sess);
@@ -575,8 +568,6 @@ cleanup:
 static void
 test_dbi_business_store_and_reload (Fixture* fixture, gconstpointer pData)
 {
-    QofSession* session_2;
-    QofSession* session_3;
     const gchar* url = (gchar*)pData;
 
     auto msg = "[GncDbiSqlConnection::unlock_database()] There was no lock entry in the Lock table";
@@ -587,14 +578,14 @@ test_dbi_business_store_and_reload (Fixture* fixture, gconstpointer pData)
     if (fixture->filename)
         url = fixture->filename;
     // Save the session data
-    session_2 = qof_session_new ();
+    auto session_2 = qof_session_new (nullptr);
     qof_session_begin (session_2, url, FALSE, TRUE, TRUE);
     qof_session_swap_data (fixture->session, session_2);
     qof_book_mark_session_dirty (qof_session_get_book (session_2));
     qof_session_save (session_2, NULL);
 
     // Reload the session data
-    session_3 = qof_session_new ();
+    auto session_3 = qof_session_new (nullptr);
     qof_session_begin (session_3, url, TRUE, FALSE, FALSE);
     qof_session_load (session_3, NULL);
 
diff --git a/libgnucash/backend/xml/test/test-load-xml2.cpp b/libgnucash/backend/xml/test/test-load-xml2.cpp
index f417fd6c2..2daa106c2 100644
--- a/libgnucash/backend/xml/test/test-load-xml2.cpp
+++ b/libgnucash/backend/xml/test/test-load-xml2.cpp
@@ -83,9 +83,6 @@ remove_locks (const char* filename)
 static void
 test_load_file (const char* filename)
 {
-    QofSession* session;
-    QofBook* book;
-    Account* root;
     gboolean ignore_lock;
     const char* logdomain = "backend.xml";
     GLogLevelFlags loglevel = static_cast<decltype (loglevel)>
@@ -94,7 +91,7 @@ test_load_file (const char* filename)
     g_log_set_handler (logdomain, loglevel,
                        (GLogFunc)test_checked_handler, &check);
 
-    session = qof_session_new ();
+    auto session = qof_session_new (nullptr);
 
     remove_locks (filename);
 
@@ -103,9 +100,9 @@ test_load_file (const char* filename)
     qof_session_begin (session, filename, ignore_lock, FALSE, TRUE);
 
     qof_session_load (session, NULL);
-    book = qof_session_get_book (session);
+    auto book = qof_session_get_book (session);
 
-    root = gnc_book_get_root_account (book);
+    auto root = gnc_book_get_root_account (book);
     do_test (gnc_account_get_book (root) == book,
              "book and root account don't match");
 
diff --git a/libgnucash/backend/xml/test/test-save-in-lang.cpp b/libgnucash/backend/xml/test/test-save-in-lang.cpp
index 670534831..e6a3919b6 100644
--- a/libgnucash/backend/xml/test/test-save-in-lang.cpp
+++ b/libgnucash/backend/xml/test/test-save-in-lang.cpp
@@ -97,9 +97,8 @@ test_file (const char* filename)
         QofSession* session;
         char* cmd;
         char* new_file = gen_new_file_name (filename, possible_envs[i]);
-        QofSession* new_session;
 
-        session = qof_session_new ();
+        auto session = qof_session_new (nullptr);
 
         qof_session_begin (session, filename, TRUE, FALSE, FALSE);
         err = qof_session_pop_error (session);
@@ -120,7 +119,7 @@ test_file (const char* filename)
         if (!g_setenv ("LANG", possible_envs[i], TRUE))
             return g_strdup ("setenv for LANG");
 
-        new_session = qof_session_new ();
+        auto new_session = qof_session_new (nullptr);
 
         qof_session_begin (new_session, new_file, FALSE, FALSE, FALSE);
         err = qof_session_pop_error (new_session);
diff --git a/libgnucash/backend/xml/test/test-xml-account.cpp b/libgnucash/backend/xml/test/test-xml-account.cpp
index 5022a9143..d336ec237 100644
--- a/libgnucash/backend/xml/test/test-xml-account.cpp
+++ b/libgnucash/backend/xml/test/test-xml-account.cpp
@@ -386,12 +386,11 @@ test_real_account (const char* tag, gpointer global_data, gpointer data)
 int
 main (int argc, char** argv)
 {
-    QofSession* session;
 
     qof_init ();
     cashobjects_register ();
-    session = qof_session_new ();
-    sixbook = qof_session_get_book (session);
+    sixbook = qof_book_new ();
+    auto session = qof_session_new (sixbook);
     if (argc > 1)
     {
         test_files_in_dir (argc, argv, test_real_account,
diff --git a/libgnucash/backend/xml/test/test-xml-pricedb.cpp b/libgnucash/backend/xml/test/test-xml-pricedb.cpp
index 18d22ef6b..4660084f7 100644
--- a/libgnucash/backend/xml/test/test-xml-pricedb.cpp
+++ b/libgnucash/backend/xml/test/test-xml-pricedb.cpp
@@ -46,7 +46,7 @@ extern "C"
 #include "test-file-stuff.h"
 #include "test-stuff.h"
 
-static QofSession* session;
+static QofSession* session = NULL;
 static int iter;
 
 static gboolean
@@ -126,9 +126,10 @@ test_generation (void)
     for (iter = 0; iter < 20; iter++)
     {
         GNCPriceDB* db;
+        auto book = qof_book_new();
         g_message ("iter=%d", iter);
-        session = qof_session_new ();
-        db = get_random_pricedb (qof_session_get_book (session));
+        session = qof_session_new (book);
+        db = get_random_pricedb (book);
         if (!db)
         {
             failure_args ("gnc_random_price_db returned NULL",
@@ -151,7 +152,6 @@ main (int argc, char** argv)
     //qof_log_init_filename("/tmp/gnctest.trace");
     //qof_log_set_default(QOF_LOG_DETAIL);
     //qof_log_set_level(GNC_MOD_PRICE, QOF_LOG_DETAIL);
-    session = qof_session_new ();
     test_generation ();
     print_test_results ();
     qof_close ();
diff --git a/libgnucash/engine/gnc-session.c b/libgnucash/engine/gnc-session.c
index 6df5868b1..7bc674c53 100644
--- a/libgnucash/engine/gnc-session.c
+++ b/libgnucash/engine/gnc-session.c
@@ -35,8 +35,9 @@ gnc_get_current_session (void)
 {
     if (!current_session)
     {
+        QofBook* book = qof_book_new ();
         qof_event_suspend();
-        current_session = qof_session_new ();
+        current_session = qof_session_new (book);
         qof_event_resume();
     }
 
diff --git a/libgnucash/engine/qofsession.cpp b/libgnucash/engine/qofsession.cpp
index a42ad0912..1db4b6b54 100644
--- a/libgnucash/engine/qofsession.cpp
+++ b/libgnucash/engine/qofsession.cpp
@@ -118,8 +118,9 @@ qof_backend_get_registered_access_method_list(void)
 /* ====================================================================== */
 /* Constructor/Destructor ----------------------------------*/
 
-QofSessionImpl::QofSessionImpl () noexcept
-    : m_book {qof_book_new ()},
+QofSessionImpl::QofSessionImpl (QofBook* book) noexcept
+  : m_backend {},
+    m_book {book},
     m_book_id {},
     m_saving {false},
     m_last_err {},
@@ -145,19 +146,19 @@ qof_session_destroy (QofSession * session)
 }
 
 QofSession *
-qof_session_new (void)
+qof_session_new (QofBook* book)
 {
-    return new QofSessionImpl;
+    return new QofSessionImpl(book);
 }
 
 void
 QofSessionImpl::destroy_backend () noexcept
 {
-    auto backend = qof_book_get_backend (m_book);
-    if (backend)
+    if (m_backend)
     {
         clear_error ();
-        delete backend;
+        delete m_backend;
+        m_backend = nullptr;
         qof_book_set_backend (m_book, nullptr);
     }
 }
@@ -187,8 +188,7 @@ QofSessionImpl::load_backend (std::string access_method) noexcept
                     prov->provider_name, m_book_id.c_str ());
             continue;
         }
-        auto backend = prov->create_backend();
-        qof_book_set_backend (m_book, backend);
+        m_backend = prov->create_backend();
         LEAVE (" ");
         return;
     }
@@ -209,12 +209,25 @@ QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
     /* At this point, we should are supposed to have a valid book
     * id and a lock on the file. */
     clear_error ();
-    auto be (qof_book_get_backend(m_book));
-    if (be)
+
+    /* This code should be sufficient to initialize *any* backend,
+    * whether http, postgres, or anything else that might come along.
+    * Basically, the idea is that by now, a backend has already been
+    * created & set up.  At this point, we only need to get the
+    * top-level account group out of the backend, and that is a
+    * generic, backend-independent operation.
+    */
+    qof_book_set_backend (newbook, m_backend);
+
+    /* Starting the session should result in a bunch of accounts
+    * and currencies being downloaded, but probably no transactions;
+    * The GUI will need to do a query for that.
+    */
+    if (m_backend)
     {
-        be->set_percentage(percentage_func);
-        be->load (m_book, LOAD_TYPE_INITIAL_LOAD);
-        push_error (be->get_error(), {});
+        m_backend->set_percentage(percentage_func);
+        m_backend->load (newbook, LOAD_TYPE_INITIAL_LOAD);
+        push_error (m_backend->get_error(), {});
     }
 
     auto err = get_error ();
@@ -225,12 +238,17 @@ QofSessionImpl::load (QofPercentageFunc percentage_func) noexcept
             (err != ERR_SQL_DB_TOO_OLD) &&
             (err != ERR_SQL_DB_TOO_NEW))
     {
-        auto old_book = m_book;
-        m_book = qof_book_new();
-        qof_book_destroy(old_book);
+        /* Something broke, put back the old stuff */
+        delete m_backend;
+        qof_book_set_backend (newbook, NULL);
+        qof_book_destroy (newbook);
+        m_book = oldbook;
+        m_backend = qof_book_get_backend (m_book);
         LEAVE ("error from backend %d", get_error ());
         return;
     }
+    qof_book_destroy (oldbook);
+
     LEAVE ("sess = %p, book_id=%s", this, m_book_id.c_str ());
 }
 
@@ -288,8 +306,7 @@ QofSessionImpl::begin (std::string new_book_id, bool ignore_lock,
     g_free (scheme);
 
     /* No backend was found. That's bad. */
-    auto backend = qof_book_get_backend (m_book);
-    if (backend == nullptr)
+    if (m_backend == nullptr)
     {
         m_book_id = {};
         if (ERR_BACKEND_NO_ERR == get_error ())
@@ -300,10 +317,11 @@ QofSessionImpl::begin (std::string new_book_id, bool ignore_lock,
     }
 
     /* If there's a begin method, call that. */
-    backend->session_begin(this, m_book_id.c_str(), ignore_lock, create, force);
+    m_backend->session_begin(this, m_book_id.c_str(),
+                             ignore_lock, create, force);
     PINFO ("Done running session_begin on backend");
-    QofBackendError const err {backend->get_error()};
-    auto msg (backend->get_message());
+    QofBackendError const err {m_backend->get_error()};
+    auto msg (m_backend->get_message());
     if (err != ERR_BACKEND_NO_ERR)
     {
         m_book_id = {};
@@ -397,7 +415,7 @@ QofSessionImpl::get_book () const noexcept
 QofBackend *
 QofSession::get_backend () const noexcept
 {
-    return qof_book_get_backend (m_book);
+    return m_backend;
 }
 
 std::string
@@ -436,13 +454,14 @@ QofSessionImpl::save (QofPercentageFunc percentage_func) noexcept
      * network has crashed, etc.)  then raise an error so that the controlling
      * dialog can offer the user a chance to save in a different way.
      */
-    auto backend = qof_book_get_backend (m_book);
-    if (backend)
+    if (m_backend)
     {
-
-        backend->set_percentage(percentage_func);
-        backend->sync(m_book);
-        auto err = backend->get_error();
+        /* if invoked as SaveAs(), then backend not yet set */
+        if (qof_book_get_backend (m_book) != m_backend)
+            qof_book_set_backend (m_book, m_backend);
+        m_backend->set_percentage(percentage_func);
+        m_backend->sync(m_book);
+        auto err = m_backend->get_error();
         if (err != ERR_BACKEND_NO_ERR)
         {
             push_error (err, {});
@@ -465,12 +484,13 @@ QofSessionImpl::save (QofPercentageFunc percentage_func) noexcept
 void
 QofSessionImpl::safe_save (QofPercentageFunc percentage_func) noexcept
 {
-    auto backend = qof_book_get_backend (m_book);
-    if (!backend) return;
-    backend->set_percentage(percentage_func);
-    backend->safe_sync(get_book ());
-    auto err = backend->get_error();
-    auto msg = backend->get_message();
+    if (!(m_backend && m_book)) return;
+    if (qof_book_get_backend (m_book) != m_backend)
+        qof_book_set_backend (m_book, m_backend);
+    m_backend->set_percentage(percentage_func);
+    m_backend->safe_sync(get_book ());
+    auto err = m_backend->get_error();
+    auto msg = m_backend->get_message();
     if (err != ERR_BACKEND_NO_ERR)
     {
         m_book_id = nullptr;
@@ -481,10 +501,11 @@ QofSessionImpl::safe_save (QofPercentageFunc percentage_func) noexcept
 void
 QofSessionImpl::ensure_all_data_loaded () noexcept
 {
-    auto backend = qof_book_get_backend (m_book);
-    if (!backend) return;
-    backend->load(m_book, LOAD_TYPE_LOAD_ALL);
-    push_error (backend->get_error(), {});
+    if (!(m_backend && m_book)) return;
+    if (qof_book_get_backend (m_book) != m_backend)
+        qof_book_set_backend (m_book, m_backend);
+    m_backend->load(m_book, LOAD_TYPE_LOAD_ALL);
+    push_error (m_backend->get_error(), {});
 }
 
 void
@@ -492,7 +513,8 @@ QofSessionImpl::swap_books (QofSessionImpl & other) noexcept
 {
     ENTER ("sess1=%p sess2=%p", this, &other);
     // don't swap (that is, double-swap) read_only flags
-    std::swap (m_book->read_only, other.m_book->read_only);
+    if (m_book && other.m_book)
+        std::swap (m_book->read_only, other.m_book->read_only);
     std::swap (m_book, other.m_book);
     auto mybackend = qof_book_get_backend (m_book);
     qof_book_set_backend (m_book, qof_book_get_backend (other.m_book));
@@ -527,13 +549,12 @@ QofSessionImpl::export_session (QofSessionImpl & real_session,
     /* There must be a backend or else.  (It should always be the file
      * backend too.)
      */
-    auto backend2 = qof_book_get_backend(m_book);
-    if (!backend2) return false;
+    if (!m_backend) return false;
 
-    backend2->set_percentage(percentage_func);
+    m_backend->set_percentage(percentage_func);
 
-    backend2->export_coa(real_book);
-    auto err = backend2->get_error();
+    m_backend->export_coa(real_book);
+    auto err = m_backend->get_error();
     if (err != ERR_BACKEND_NO_ERR)
         return false;
     return true;
diff --git a/libgnucash/engine/qofsession.h b/libgnucash/engine/qofsession.h
index dafa43756..88b7b2546 100644
--- a/libgnucash/engine/qofsession.h
+++ b/libgnucash/engine/qofsession.h
@@ -114,7 +114,7 @@ extern "C"
 
 typedef struct QofSessionImpl QofSession;
 
-QofSession * qof_session_new (void);
+QofSession * qof_session_new (QofBook* book);
 void         qof_session_destroy (QofSession *session);
 
 /** The qof_session_swap_data () method swaps the book of
diff --git a/libgnucash/engine/qofsession.hpp b/libgnucash/engine/qofsession.hpp
index 7820e08ca..12a92b16b 100644
--- a/libgnucash/engine/qofsession.hpp
+++ b/libgnucash/engine/qofsession.hpp
@@ -36,7 +36,7 @@
 
 struct QofSessionImpl
 {
-    QofSessionImpl () noexcept;
+    QofSessionImpl (QofBook* book = nullptr) noexcept;
     /* Ends the current session, destroys the backend, and destroys the book.  */
     ~QofSessionImpl () noexcept;
 
@@ -85,10 +85,13 @@ private:
 
     void load_backend (std::string access_method) noexcept;
 
+    /* The backend. We store this during startup to avoid having to create a
+     * book just to hold it.
+     */
+    QofBackend* m_backend;
     /* A book holds pointers to the various types of datasets.
      * A session has exactly one book. */
     QofBook * m_book;
-
     /* The requested book id, in the form or a URI, such as
      * file:/some/where, or sql:server.host.com:555
      */
diff --git a/libgnucash/engine/test-core/test-engine-stuff.cpp b/libgnucash/engine/test-core/test-engine-stuff.cpp
index 13ec7af8d..bd0b86216 100644
--- a/libgnucash/engine/test-core/test-engine-stuff.cpp
+++ b/libgnucash/engine/test-core/test-engine-stuff.cpp
@@ -1875,12 +1875,8 @@ get_random_book (void)
 QofSession *
 get_random_session (void)
 {
-    QofSession *session;
-    QofBook *book;
-
-    session = qof_session_new ();
-
-    book = qof_session_get_book (session);
+    auto book = qof_book_new ();
+    auto session = qof_session_new (book);
 
     get_random_account_tree (book);
     get_random_pricedb (book);
diff --git a/libgnucash/engine/test/test-qofsession-old.cpp b/libgnucash/engine/test/test-qofsession-old.cpp
index 20dc52078..d9be207f3 100644
--- a/libgnucash/engine/test/test-qofsession-old.cpp
+++ b/libgnucash/engine/test/test-qofsession-old.cpp
@@ -70,7 +70,7 @@ percentage_fn ( const char* message, double percent )
 static void
 setup( Fixture *fixture, gconstpointer pData )
 {
-    fixture->session = qof_session_new();
+    fixture->session = qof_session_new (qof_book_new ());
     init_static_qofsession_pointers ();
     g_assert (p_qof_session_clear_error && p_qof_session_destroy_backend && p_qof_session_load_backend);
 }
@@ -87,14 +87,11 @@ teardown( Fixture *fixture, gconstpointer pData )
 static void
 test_qof_session_new_destroy (void)
 {
-    QofSession *session = NULL;
-    QofBook *book = NULL;
-
     g_test_message ("Test session initialization");
-    session = qof_session_new ();
+    auto session = qof_session_new (qof_book_new ());
     g_assert (session);
     g_assert (qof_session_get_book (session));
-    book = (QofBook*) qof_session_get_book (session);
+    auto book = qof_session_get_book (session);
     g_assert (book);
     g_assert (QOF_IS_BOOK (book));
     g_assert (!strlen (qof_session_get_url (session)));
@@ -584,11 +581,9 @@ mock_export (QofBackend *be, QofBook *book)
 static void
 test_qof_session_export (Fixture *fixture, gconstpointer pData)
 {
-    QofSession *real_session = NULL;
-    QofBook *tmp_book = NULL, *real_book = NULL;
     QofBackend *be = NULL;
 
-    real_session = qof_session_new ();
+    auto real_session = qof_session_new (qof_book_new ());
     g_assert (real_session);
 
     g_test_message ("Test null checks");
@@ -596,9 +591,9 @@ test_qof_session_export (Fixture *fixture, gconstpointer pData)
     g_assert (!qof_session_export (fixture->session, NULL, percentage_fn));
 
     g_test_message ("Test with backend not set");
-    tmp_book = qof_session_get_book (fixture->session);
+    auto tmp_book = qof_session_get_book (fixture->session);
     g_assert (tmp_book);
-    be = qof_book_get_backend (tmp_book);
+    auto be = qof_book_get_backend (tmp_book);
     g_assert (!be);
     g_assert (!qof_session_export (fixture->session, real_session, percentage_fn));
 
@@ -616,7 +611,7 @@ test_qof_session_export (Fixture *fixture, gconstpointer pData)
     qof_backend_set_error (be, ERR_BACKEND_DATA_CORRUPT);
     qof_backend_set_message (be, "push any error");
     session_export_struct.called = FALSE;
-    real_book = qof_session_get_book (real_session);
+    auto real_book = qof_session_get_book (real_session);
     g_assert (real_book);
     session_export_struct.be = be;
     session_export_struct.book = real_book;
@@ -641,7 +636,7 @@ test_qof_session_swap_data (Fixture *fixture, gconstpointer pData)
 
     /* init */
     g_assert (fixture->session);
-    session2 = qof_session_new ();
+    auto session2 = qof_session_new (qof_book_new ());
     g_assert (session2);
     g_assert (fixture->session != session2);
     be1 = g_new0 (QofBackend, 1);
diff --git a/libgnucash/engine/test/test-qofsession.cpp b/libgnucash/engine/test/test-qofsession.cpp
index fd53b1ce2..ae9b57311 100644
--- a/libgnucash/engine/test/test-qofsession.cpp
+++ b/libgnucash/engine/test/test-qofsession.cpp
@@ -105,9 +105,9 @@ get_provider ()
 TEST (QofSessionTest, swap_books)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s1;
+    QofSession s1(qof_book_new());
     s1.begin ("book1", false, false, false);
-    QofSession s2;
+    QofSession s2(qof_book_new());
     s2.begin ("book2", false, false, false);
     QofBook * b1 {s1.get_book ()};
     QofBook * b2 {s2.get_book ()};
@@ -121,7 +121,7 @@ TEST (QofSessionTest, swap_books)
 TEST (QofSessionTest, ensure_all_data_loaded)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     data_loaded = false;
     s.ensure_all_data_loaded ();
@@ -132,7 +132,7 @@ TEST (QofSessionTest, ensure_all_data_loaded)
 TEST (QofSessionTest, get_error)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     s.ensure_all_data_loaded ();
     EXPECT_NE (s.get_error (), ERR_BACKEND_NO_ERR);
@@ -144,7 +144,7 @@ TEST (QofSessionTest, get_error)
 TEST (QofSessionTest, pop_error)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     //We run the test first, and make sure there is an error condition.
     s.ensure_all_data_loaded ();
@@ -156,7 +156,7 @@ TEST (QofSessionTest, pop_error)
 TEST (QofSessionTest, clear_error)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     //We run the test first, and make sure there is an error condition.
     s.ensure_all_data_loaded ();
@@ -199,7 +199,7 @@ TEST (QofSessionTest, load)
 TEST (QofSessionTest, save)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     load_error = false;
     s.load (nullptr);
@@ -214,7 +214,7 @@ TEST (QofSessionTest, save)
 TEST (QofSessionTest, safe_save)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s;
+    QofSession s(qof_book_new());
     s.begin ("book1", false, false, false);
     s.safe_save (nullptr);
     EXPECT_EQ (safe_sync_called, true);
@@ -225,14 +225,14 @@ TEST (QofSessionTest, safe_save)
 TEST (QofSessionTest, export_session)
 {
     qof_backend_register_provider (get_provider ());
-    QofSession s1;
+    auto b1 = qof_book_new();
+    QofSession s1(b1);
     s1.begin ("book1", false, false, false);
-    QofSession s2;
+    qof_book_set_backend(b1, s1.get_backend());
+    auto b2 = qof_book_new();
+    QofSession s2(b2);
     s2.begin ("book2", false, false, false);
-    QofBook * b1 = s1.get_book ();
-    QofBook * b2 = s2.get_book ();
-    b1->backend = s1.get_backend ();
-    b2->backend = s2.get_backend ();
+    qof_book_set_backend(b2, s2.get_backend());
     s2.export_session (s1, nullptr);
     EXPECT_EQ (exported_book, b1);
 
diff --git a/libgnucash/engine/test/test-split-vs-account.cpp b/libgnucash/engine/test/test-split-vs-account.cpp
index d51ac2a08..ee1e320a1 100644
--- a/libgnucash/engine/test/test-split-vs-account.cpp
+++ b/libgnucash/engine/test/test-split-vs-account.cpp
@@ -38,19 +38,12 @@ extern "C"
 static void
 run_test (void)
 {
-    Account *act1;
-    Account *act2;
-    //Split *spl;
-    QofSession *session;
-    QofBook *book;
+    auto book = qof_book_new ();
 
-    session = qof_session_new ();
-    book = qof_session_get_book (session);
-
-    act1 = get_random_account(book);
+    auto act1 = get_random_account(book);
     do_test(act1 != NULL, "random account created");
 
-    act2 = get_random_account(book);
+    auto act2 = get_random_account(book);
     do_test(act2 != NULL, "random account created");
 #if 0
     spl = get_random_split(book, act1, NULL);



Summary of changes:
 bindings/engine.i                                  |   3 +-
 bindings/guile/test/test-create-account.scm        |   3 +-
 bindings/python/gnucash_core.i                     |   3 +-
 bindings/python/gnucash_core.py                    |   2 +-
 bindings/python/sqlite3test.c                      |   6 +-
 gnucash/gnome-utils/assistant-xml-encoding.c       |   2 +-
 gnucash/gnome-utils/gnc-file.c                     |  21 +++-
 gnucash/gnome/gnc-plugin-basic-commands.c          |  13 +++
 gnucash/import-export/aqb/test/test-kvp.c          |   6 +-
 .../backend/dbi/test/test-backend-dbi-basic.cpp    |  45 ++++----
 libgnucash/backend/xml/test/test-load-xml2.cpp     |   9 +-
 libgnucash/backend/xml/test/test-save-in-lang.cpp  |   5 +-
 libgnucash/backend/xml/test/test-xml-account.cpp   |   5 +-
 libgnucash/backend/xml/test/test-xml-pricedb.cpp   |   8 +-
 libgnucash/engine/Account.cpp                      |   4 +-
 libgnucash/engine/gnc-session.c                    |   3 +-
 libgnucash/engine/qofsession.cpp                   | 120 ++++++++++++---------
 libgnucash/engine/qofsession.h                     |   2 +-
 libgnucash/engine/qofsession.hpp                   |   7 +-
 libgnucash/engine/test-core/test-engine-stuff.cpp  |   8 +-
 libgnucash/engine/test/test-qofsession-old.cpp     |  21 ++--
 libgnucash/engine/test/test-qofsession.cpp         |  44 ++++----
 libgnucash/engine/test/test-split-vs-account.cpp   |  13 +--
 23 files changed, 193 insertions(+), 160 deletions(-)



More information about the gnucash-changes mailing list